2017-09-28 3 views
0

Je voudrais savoir s'il existe une façon plus élégante de chaîner has_many à travers les relations. Dans mon exemple, j'ai un utilisateur qui peut avoir plusieurs rôles. Chaque rôle a plusieurs autorisations. Un utilisateur a donc plusieurs autorisations. Le code ci-dessous fonctionne bien, mais je me demande s'il existe une meilleure façon de le faire.Chaîne has_many: par le biais des associations

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 

Je voudrais pouvoir faire ceci.

user.permissions 

EDIT: J'ai essayé Une chose que j'ai essayé au moins Drys le modèle de l'utilisateur un peu ajoute la fonction comme une préoccupation

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 

Répondre

3

Avez-vous essayé ..

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

Cela devrait vous donner

user.permissions 

Je ne sais pas quand la HMT via la fonctionnalité HMT a été mis à la disposition, je sais qu'il manquait dans les versions antérieures de rails, mais cela fonctionne pour moi sur Rails 5.

1

Si vous faites ceci:

class Permission < ActiveRecord::Base 
    has_many :permission_role_mappings 
end 

Ensuite, vous devriez être en mesure de le faire:

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  

Par ailleurs, vous savez peut-être cela et il peut être la raison pour laquelle vous posez la question ... mais cela va vous donner une N + 1 requête:

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

En outre, FWIW , lorsque l'on veut un array retour d'une collection, vous n'avez pas besoin de le faire:

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

vous pouvez juste faire:

roles.map do |role| 
    ... 
    end 

Depuis map renvoie un array.