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

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, -&gt; 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】:

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

【讨论】:

这是正确答案。创建时的关联不知道业务逻辑,因此,如果当时创建它们,则无法创建或阻止它们。它们只能被使用,然后根据条件进行过滤。

以上是关于是否可以在模型中创建条件关联?的主要内容,如果未能解决你的问题,请参考以下文章

在相关模型中通过多个参数找到记录的条件?

在 Blender 中创建的 3D 模型上使用材质

如何在rails 4中创建新的belongs_to关联模型

通过 XNA 在 Motion Builder 中创建 FBX 模型

如何在 Sequelize 中创建关联

为续集自动生成模型