Rails 3 has_many:通过+连接表条件/范围

Jer*_*iko 9 activerecord arel ruby-on-rails-3

我的工作是有模型的应用程序UserProject,并User可以被分配到多个ProjectS,通过ProjectUser与一个角色(如开发人员,设计师).

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
Run Code Online (Sandbox Code Playgroud)

我可以打电话@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'
Run Code Online (Sandbox Code Playgroud)

我目前有以下代码:

has_many :developers, :through => :project_users, :source => :user,
                      :class_name => "User",
                      :conditions => ['project_users.role = ?','Developer']
Run Code Online (Sandbox Code Playgroud)

但这只是单向提取,并没有给我太多其他东西 - 我无法建立或分配或任何东西.

我正在尝试一些我认为可能有用的更复杂的逻辑,但我会欣赏一些指示:

has_many :developer_assignments, :source => :project_user,
                                 :conditions => { :role => 'Developer' }
has_many :developers, :through => :developer_assignments # class_name?
Run Code Online (Sandbox Code Playgroud)

有什么建议?谢谢!

Hec*_*lot 12

has_many接受可以定义/覆盖关联方法的块.这将允许您为其创建自定义方法<<.我为你创建了一个小例子,你可以用类似的方式创建构建.

# 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
Run Code Online (Sandbox Code Playgroud)

现在,您可以@project.developers << @user根据要求为项目添加新的开发人员.@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
Run Code Online (Sandbox Code Playgroud)

回首这一切上面似乎并不像铁轨的方式做事.确定范围应该可以使构建和创建命令工作而无需重新定义所有内容.

希望这可以帮助!


Ahm*_*ish 1

听起来您正在寻找的是 RoR 的单表继承命名范围的组合。

请参阅以下文章,了解有关多态关联的一个很好的示例。这应该可以帮助您实现以下目标:

@project.developers
  # returns @project.users, but only where ProjectUser.role = 'Developer'

@project.designers << @user
  # creates a ProjectUser for @project, @user with role 'Designer'
Run Code Online (Sandbox Code Playgroud)

范围将为您提供一种干净的实施方式@user.development_projects,但可能需要更多技巧才能获得<<操作员。