Reputation: 2461
I would like to know if there is a more elegant way to chain has_many through relationships. In my example I have a user whom can have multiple roles. Each role has multiple permissions. So a user has multiple permissions. The code below works fine, but I am wonder if there is a better way to do this.
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
I would like to be able to do this.
user.permissions
EDIT: Tried On thing that I tried that at least DRYs the User model a little bit is adding the function as a concern
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
Upvotes: 0
Views: 1338
Reputation: 20263
If you do this:
class Permission < ActiveRecord::Base
has_many :permission_role_mappings
end
Then you should be able to do this:
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
By the way, you may already know this and it may be why you're asking the question... but this is going to give you an N+1 query:
permitted_actions = []
self.roles.each do |role|
role.permissions.each do |permission|
permitted_actions << permission
end
end
permitted_actions
Also, FWIW, when wanting an array
back from a collection, you don't need to do:
permitted_actions = []
self.roles.each do |role|
...
end
permitted_actions
You can just do:
roles.map do |role|
...
end
Since map
returns an array
.
Upvotes: 1
Reputation: 36860
Have you tried..
class User < ActiveRecord::Base
has_many :role_user_mappings
has_many :roles, through: :role_user_mappings
has_many :permissions, through: roles
That should give you
user.permissions
I'm not sure when the HMT via HMT feature was made available, I know it was missing in earlier versions of rails, but it works for me on Rails 5.
Upvotes: 4