Rails 3中的has_many:通过加入+表条件/作用域
我的工作具有模型User
和Project
,并且User
可以分配给多个Project
秒的应用程序,通过ProjectUser
,与角色(如开发人员,设计师)。Rails 3中的has_many:通过加入+表条件/作用域
Project
has_many :project_users
has_many :users, :through => :project_users
User
has_many :project_users
has_many :projects, :through => :project_users
ProjectUser (user_id, project_id, role)
belongs_to :user
belongs_to :project
我可以打电话@project.users
和@user.projects
,但既然有不同的角色,我想成为一个更具体一点与关系。理想情况下,我希望能够做到以下几点:
@project.developers
# returns @project.users, but only where ProjectUser.role = 'Developer'
@project.designers << @user
# creates a ProjectUser for @project, @user with role 'Designer'
@user.development_projects
# returns projects where @user is assigned as a 'Developer'
@user.design_projects << @project
# creates a ProjectUser for @project, @user with role 'Designer'
目前,我有以下代码:
has_many :developers, :through => :project_users, :source => :user,
:class_name => "User",
:conditions => ['project_users.role = ?','Developer']
但这只是确实在获取单向的,并且不给我别的 - 我不能建立或分配任何东西。
我试图一些更复杂的逻辑,我认为可能的工作,但希望得到一些指点:
has_many :developer_assignments, :source => :project_user,
:conditions => { :role => 'Developer' }
has_many :developers, :through => :developer_assignments # class_name?
有什么建议?谢谢!
这听起来像你正在寻找的是RoR的single table inheritance和named scopes的组合。
查看下面的article关于多态关联的一个很好的例子。这应该可以帮助你达到以下:
@project.developers
# returns @project.users, but only where ProjectUser.role = 'Developer'
@project.designers << @user
# creates a ProjectUser for @project, @user with role 'Designer'
作用域会给你一个干净的方式来实现@user.development_projects
但也有可能获得<<
运营商需要更多的挂羊头卖狗肉。
has_many
接受可定义/覆盖关联方法的块。这将允许您为<<
创建自定义方法。我为你创建了一个小例子,你可以用类似的方式创建构建。根据要求@project.developers << @user
:
# 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
现在你可以添加一个新的开发你的项目有。 @project.developers
为您提供所有开发人员。
如果您有很多角色,则动态创建这些has_many语句可能会很有用。
# 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
回顾上面的一切似乎并不像做事方式轨道。范围这应该使得构建和创建命令成为可能,而不用重新定义所有的东西。
希望这会有所帮助!
您是否尝试过使用scopes呢?它不会让你做< <。但它简化了查询。
尝试:
Project
scope :developers, lambda {
includes(:project_users).where("project_users.role = ?", "developer")
}
您将能够获得使用所有开发人员:@project.developers
谢谢您的回答。它解决了我的问题,但并未按照我希望的方式这样做 - 通过在“ProjectUsers”模型上使用范围。 声明':conditions =>“project_users.role ='#{role}'”'看起来好像不是很有道理,因为我喜欢调用像':conditions => {:scope =>:developer}' 。我仍然肯定这是可能的。无论哪种方式,我都会奖励你为你付出的努力,尽管这个答案不会被标记为正确的。感谢您的输入! – Jeriko
谢谢。我真的希望'has_many:designers,:through =>:project_users,:source =>:user,:conditions => {:project_users => {:role =>:designer}}'自动工作,但显然是嵌套条件哈希不在构建和创建范围内。这是我能想到的最好的。 – HectorMalot
以上是什么'proxy_owner'?是指对assiociation的另一方,类似于你用':extend'得到的'proxy_association'? – sbeam