I\'m working on an app that has the models User
and Project
, and User
can be assigned to multiple Project
s, via Project
It sounds like what you're looking for is a combination of RoR's single table inheritance and named scopes.
Take a look at the following article for a nice example about polymorphic associations. This should help you with achieving the following:
@project.developers
# returns @project.users, but only where ProjectUser.role = 'Developer'
@project.designers << @user
# creates a ProjectUser for @project, @user with role 'Designer'
Scopes will give you a clean way to implement @user.development_projects
but there may be more trickery required to get the <<
operator.
Did you try using scopes yet? It doesn't let you do <<. But it simplifies querying.
Try:
Project
scope :developers, lambda {
includes(:project_users).where("project_users.role = ?", "developer")
}
You will be able to get all developers using: @project.developers
has_many
accepts a block that can define/override methods for the association. This will allow you to create a custom method for <<
. I've created a small example for you, you could create build in a similar fashion.
# Project.rb
has_many :developers, :through => :project_users, :source => :user,
:conditions => "project_users.role = 'developer'" do
def <<(developer)
proxy_owner.project_users.create(:role => 'developer', :user => developer)
end
end
Now you can add a new developer to your your project with: @project.developers << @user
as requested. @project.developers
gives you all the developers.
If you have a lot of roles, it might be useful to create these has_many statements dynamically.
# Project.rb
ROLES = ['developer','contractor']
ROLES.each do |role|
self.class_eval <<-eos
has_many :#{role.downcase}s, :through => :project_users, :source => :user,
:conditions => "project_users.role = '#{role}'" do
def <<(user)
proxy_owner.project_users.create(:role => '#{role}', :user => user)
end
end
eos
end
Looking back at everything above it doesn't seem like the rails way of doing things. Scoping this should make it possible to get the build and create commands working without redefining everything.
Hope this helps!