是否可以在模型中创建条件关联?
Posted
技术标签:
【中文标题】是否可以在模型中创建条件关联?【英文标题】:Is it possible to create a conditional association in model? 【发布时间】:2012-03-22 07:19:48 【问题描述】:我已经建立了一个基于角色的访问控制系统,具有以下模型:
角色(作为 STI), UserRole(全局角色) ProjectRole(项目特定角色) 分配(具有不同资源的多态) 用户 项目(作为分配的一种资源类型)只有拥有特定 UserRole 的用户才能对项目负责。 此用户角色名为“负责项目”,ID 为 2。
在用户模型中有两个has_many关联:responsible_assignments和responsible_projects。 仅当用户具有 ID 为 2 的 UserRole“负责项目”时,此关联才有效。
是否可以在用户模型中为责任_* 关联创建条件关联,这是建立这种关系的常用方法吗?
解决此类问题的最佳做法是什么?
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
...
【问题讨论】:
条件关联是什么意思?有什么条件? 条件是:如果用户没有id为2的角色,则责任_*关联无效/不应设置。 【参考方案1】:我认为即使从 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?
不确定这种解决方案的含义(父级将有条件地看不到子级,因此如果需要,将不会调用销毁回调等)
【讨论】:
【参考方案2】:万一以后有人发现 - 这个功能现在实际上在 rails 4 中可用:
http://guides.rubyonrails.org/association_basics.html
语法是:
has_many :orders, -> where processed: true
【讨论】:
非常感谢!我还需要关联的自定义名称,所以我可以使用 class_name:has_many :processed_orders, -> where processed: true , class_name: "Order"
我不认为这解决了原始问题的问题,因为它允许您按关联对象的字段进行过滤。但是问题的作者希望仅在用户的 role_id 具有特定值时才有条件工作
这不是正确的答案。 OP 正在寻找会导致关联基于条件存在的东西。如果满足该条件,则只有在这种情况下关联才应该存在,否则不存在。【参考方案3】:
您不能将这些条件放在关联中。这样的事情是在范围内处理的。
阅读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
【讨论】:
【参考方案4】:这些关联是在加载模型时创建的。你当时的情况是未知的。 您只能在关联中包含条件以过滤掉不需要的记录。
【讨论】:
这是正确答案。创建时的关联不知道业务逻辑,因此,如果当时创建它们,则无法创建或阻止它们。它们只能被使用,然后根据条件进行过滤。以上是关于是否可以在模型中创建条件关联?的主要内容,如果未能解决你的问题,请参考以下文章