有关动态定义类和实例方法

时间:2015-09-15 08:15:15

标签: ruby-on-rails ruby metaprogramming activesupport-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

正如您所看到的,它定义了一堆范围,类方法和实例方法。但我对重复Role.find_each do |role| ... end感到不满。

如何消除这种重复?我试过这个

Role.find_each do |role|
  included do
    ...
  end
  class_methods do
    ...
  end
end

但由于多个included块,它无法正常工作。 我可以在方法中提取Role.find_each,但效果不是很好。

如何改进此代码并删除重复?

2 个答案:

答案 0 :(得分:3)

我认为你的逻辑错误。您不应该使用Role.find_each,因为在初始化基类之后新角色将不可用,或者您必须在每次需要时明确加载您的注意事项。

rolify 中,您有一些有用的方法:

Forum.with_role(:admin)
Forum.with_role(:admin, current_user)
@user.has_role?(:forum, Forum)
...

答案 1 :(得分:0)

如果您非常确定您的角色库存不会扩展,那么也许您可以动态定义一堆匿名问题,而不是为所有角色创建一个问题。

# 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

并将所有这些问题包含在您的模型中:

# models/user.rb
class User
  Rolables.each{|concern| include concern}
end