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
.
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?
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