通过 Rails 5 中的另一个模型继承关联

Posted

技术标签:

【中文标题】通过 Rails 5 中的另一个模型继承关联【英文标题】:Inheriting an association via another model in Rails 5 【发布时间】:2019-06-27 14:17:03 【问题描述】:

我正在进行一个非常标准的用户/角色设置(用户 HABTM 角色,角色 HABTM 用户)。我正在使用 CanCanCan 进行授权,您所拥有的角色定义了您可以围绕应用程序执行的操作。这部分一切正常,但现在我希望能够让用户继承角色,作为订阅不同成员资格的一部分。

以下是相关型号:

class User < ApplicationRecord
  has_and_belongs_to_many :roles
  has_one :membership_subscription
  has_one :membership, through: :membership_subscription
end

class Role < ApplicationRecord
  has_and_belongs_to_many :users
end

class MembershipSubscription < ApplicationRecord
  belongs_to :user
  belongs_to :membership
end

class Membership < ApplicationRecord
  has_many :membership_subscriptions
  has_many :users, through: :membership_subscriptions
end

我在想我也许可以只添加一个has_many: roles 关联到会员资格,然后说用户has_many 角色通过他们订阅会员资格,以及当前允许角色的HABTM 关联直接分配。

通过这种方式,您可以像现在一样直接将角色附加到用户(因为某些角色是附加的,与会员订阅/类型完全无关),但用户也会自动继承角色(并再次失去它们)作为他们的会员来来去去。

这有意义吗?我想另一种选择是在模型中使用回调来处理创建/删除角色关联,但它看起来并不优雅。

非常感谢任何建议!

【问题讨论】:

【参考方案1】:

好的,我认为这是一个有效的答案:

首先,更新模型,以便在成员资格和角色之间建立关联:

class Role < ApplicationRecord
  has_and_belongs_to_many :users
  has_and_belongs_to_many :memberships
end

class Membership < ApplicationRecord
  has_many :membership_subscriptions
  has_many :users, through: :membership_subscriptions
  has_and_belongs_to_many :roles
end

接下来,在用户模型中创建一个可用于检索直接分配的角色和继承的角色的方法:

def combined_roles
  if self.membership == nil
    self.roles
  else
    self.roles + self.membership.roles
  end
end

然后在需要检查角色的任何地方,调用该方法而不是通常的user.roles

不确定这是否是一种幼稚的做事方式,但似乎可以正常工作。如果有更好的方法,仍然欢迎评论

编辑:

这允许用户多次拥有相同的角色 - 它可以直接分配或继承。修改 combine_roles 方法,使其去除重复项:

def combined_roles
  if self.membership == nil
    self.roles
  else
    (self.roles + self.membership.roles).uniq
  end
end

【讨论】:

最后一件事要注意 - 通过运行self.roles + self.membership.roles,您可以将 ActiveRecord 集合转换为数组。所以像.where 这样的方法不再起作用。例如,我必须更新我的 has_role 方法以使用 self.combined_roles.any? |h| h[:name] == role_name 而不是以前的 self.roles.where(:name =&gt; role_name).present? 您可以获取roles_ids 和membership.roles_ids,合并这些数组,然后执行Role.where(id: combined_roles_ids) 以使用activerecord 的查询而不是数组。

以上是关于通过 Rails 5 中的另一个模型继承关联的主要内容,如果未能解决你的问题,请参考以下文章

带有has_many的模型中的属性总和:通过关联在Rails 5中不起作用

如何在has_many中获取模型的属性:通过Rails 5中的关联

通过rails中关联模型的子类查询

通过Rails中的关联使用has_many创建新模型时出现不允许的参数错误

如何在Rails 5中删除模型时删除模型的所有关联

复杂的 Rails 模型/关联