是否可以在模型中创建条件关联?

时间:2012-03-04 15:31:19

标签: ruby-on-rails conditional has-many polymorphic-associations single-table-inheritance

我已经设置了一个基于角色的访问控制系统,其中包含以下模型:

  • 角色(作为STI),
    • UserRole(全局角色)
    • ProjectRole(项目特定角色)
  • 作业(具有不同资源的多态)
  • 用户
  • 项目(作为分配的一种资源类型)

如果项目具有特定的UserRole,则只允许用户负责项目。 此Userrole名称为“负责项目”,ID为2。

在用户模型中,有两个has_many关联:responsible_assignments和responsible_projects。 只有当用户具有ID为“负责项目”的UserRole时,此关联才有效。

是否可以在用户模型中为responsible_ *关联创建条件关联,这是设置此类关系的常用方法吗?

解决此类问题的最佳做法是什么?

class Role < ActiveRecord::Base
  has_many :assignments
  has_many :users, :through => :assignments

class UserRole < Role

class ProjectRole < Role

class Assignment < ActiveRecord::Base
  belongs_to :user
  belongs_to :role
  belongs_to :resource, :polymorphic => true

class User < ActiveRecord::Base
  has_many :assignments
  has_many :roles, :through => :assignments, 
                   :class_name => "UserRole"
  has_many :responsible_assignments, :class_name => "Assignment",
                                     :conditions => { :role_id => 4 }     // specific project role
  has_many :responsible_projects, :through => :responsible_assignments, 
                                 :source => :resource, 
                                 :source_type => 'Project',
                                 :conditions => { :status => 1 }          // project is active
  ...

class Project < ActiveRecord
  ...

4 个答案:

答案 0 :(得分:27)

如果以后有人发现这个 - 此功能现在实际上可用于rails 4:

http://guides.rubyonrails.org/association_basics.html

语法是:

has_many :orders, -> { where processed: true }

答案 1 :(得分:8)

你不能把这些条件放在关联中。这些事情在范围内处理。

阅读http://guides.rubyonrails.org/active_record_querying.html#scopes了解详情。

您的情况示例,

您希望具有特定项目角色的用户下的所有分配(ID)

scope :responsible_users, where('users.role_id = 4')
scope :select_assignment_ids, select('assignments.id')
scope :responsible_assignments, joins(:assignments).responsible_users.select_assignment_ids

您希望具有特定项目角色的用户下的所有项目(ID)都处于活动状态。

scope :active_projects, where('projects.status = 1')
scope :select_project_ids, select('projects.id')
scope :responsible_projects, joins(:assignments => :projects).responsible_users.active_projects.select_project_ids

答案 2 :(得分:1)

在加载模型时创建这些关联。那时你的病情不明。 您只能在关联中包含条件以过滤掉不需要的记录。

答案 3 :(得分:0)

我认为即使从 Rails 4.0 开始,但肯定在 5 之后,您可以像这样使用 lambda:

has_many :orders, ->(self_obj) { where('2 = ?', self_obj.role_id }

更一般地说:

has_many :children, ->(parent) { where('true = ?', parent.should_have_children? }

不确定此类解决方案的含义(父级将有条件地看不到子级,因此在需要时不会调用销毁回调等)