【问题标题】:Inheriting an association via another model in Rails 5通过 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 关联直接分配。

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

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

非常感谢任何建议!

【问题讨论】:

    标签: ruby-on-rails activerecord authorization associations roles


    【解决方案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 的查询而不是数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 2012-10-06
    • 2012-05-02
    相关资源
    最近更新 更多