Chain has_many :通过关联

Chain has_many :through associations

我想知道是否有更优雅的方式来链接 has_many 通过关系。在我的示例中,我有一个可以拥有多个角色的用户。每个角色都有多个权限。所以一个用户有多个权限。下面的代码工作正常,但我想知道是否有更好的方法来做到这一点。

class User < ActiveRecord::Base
  has_many :role_user_mappings
  has_many :roles, through: :role_user_mappings

  def permissions
    permitted_actions = []
    self.roles.each do |role|
       role.permissions.each do |permission|
         permitted_actions << permission
       end
    end
    permitted_actions
  end
end

class Role < ActiveRecord::Base
  has_many :permission_role_mappings
  has_many :permissions, through: :permission_role_mappings
end

class Permission < ActiveRecord::Base
end

class PermissionRoleMapping < ActiveRecord::Base
  belongs_to :permission
  belongs_to :role
end

class RoleUserMapping < ActiveRecord::Base
  belongs_to :user
  belongs_to :role
end

我希望能够做到这一点。

user.permissions

编辑:已尝试 在我尝试过的事情上,至少 DRYs 用户模型正在添加函数作为关注点

module Permittable
  extend ActiveSupport::Concern

  def permissions
    permitted_actions = []
    self.roles.each do |role|
       role.permissions.each do |permission|
         permitted_actions << permission
       end
    end
    permitted_actions
  end
end

如果你这样做:

class Permission < ActiveRecord::Base
  has_many :permission_role_mappings
end

那么你应该可以做到:

class User < ActiveRecord::Base
  has_many :role_user_mappings
  has_many :roles, through: :role_user_mappings

  def permissions
    Permission.
      joins(:permission_role_mappings).
      where(permission_role_mappings: {role: roles})
  end
end    

顺便说一句,您可能已经知道这一点,这可能就是您问这个问题的原因...但这会给您一个 N+1 查询:

  permitted_actions = []
  self.roles.each do |role|
     role.permissions.each do |permission|
       permitted_actions << permission
     end
  end
  permitted_actions

此外,FWIW,当想要从集合中取回 array 时,您不需要执行以下操作:

  permitted_actions = []
  self.roles.each do |role|
     ...
  end
  permitted_actions

你可以这样做:

  roles.map do |role|
    ...
  end

因为 map returns array.

你试过了吗..

class User < ActiveRecord::Base
  has_many :role_user_mappings
  has_many :roles, through: :role_user_mappings
  has_many :permissions, through: roles

那应该给你

user.permissions

我不确定 HMT via HMT 功能何时可用,我知道它在 rails 的早期版本中缺失,但它适用于 Rails 5.