I have a concern:
# app/models/concerns/rolable.rb
module Rolable
extend ActiveSupport::Concern
included do
rolify
Role.find_each do |role|
scope "#{role.name.pluralize}", -> { joins(:roles).where(roles: {name: send("#{role.name}_role_name")}).distinct }
end
end
class_methods do
Role.find_each do |role|
define_method "#{role.name}_role_name" do
role.name
end
define_method "#{role.name}_role_id" do
role.id
end
end
end
Role.find_each do |role|
define_method("#{role.name}?") do
has_role? self.class.send("#{role.name}_role_name")
end
end
end
As you can see it defines a bunch of scopes, class methods and instance methods. But I'm not happy about repetition of Role.find_each do |role| ... end
Role.find_each do |role| ... end
.
How can I eliminate this duplication? I tried this
Role.find_each do |role|
included do
...
end
class_methods do
...
end
end
But it doesn't work because of multiple included
blocks. I can extract Role.find_each
in method, but it's not much better.
How can improve this code and remove duplication?
I think you have a bad logic here. You shouldn't use Role.find_each
because new roles will not be available after initialize you base class or you will have to load explicitly your concern every time when you need it.
In rolify you have useful methods:
Forum.with_role(:admin)
Forum.with_role(:admin, current_user)
@user.has_role?(:forum, Forum)
...
If you are pretty sure that your inventory of roles won't expand, then maybe you can dynamically define a bunch of anonymous concerns instead of creating one concern for all roles.
# models/concerns/rolables.rb
# no need to call `find_each' because the number or roles will never exceed 1000
Rolables = Role.all.map do |role|
Module.new do
extend ActiveSupport::Concern
included do
scope "#{role.name.pluralize}", -> { joins(:roles).where(roles: {name: send("#{role.name}_role_name")}).distinct }
define_method("#{role.name}?") do
has_role? self.class.send("#{role.name}_role_name")
end
end
class_methods do
define_method "#{role.name}_role_name" do
role.name
end
define_method "#{role.name}_role_id" do
role.id
end
end
end
end
And include all those concerns into your model:
# models/user.rb
class User
Rolables.each{|concern| include concern}
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.