简体   繁体   English

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

[英]Define class and instance methods dynamically in concern

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感到高兴 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. 但由于多个included块,它不起作用。 I can extract Role.find_each in method, but it's not much better. 我可以在方法中提取Role.find_each ,但它并没有好多少。

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. 您不应该使用Role.find_each因为在初始化基类之后新角色将不可用,或者您必须在每次需要时明确加载您的关注点。

In rolify you have useful methods: rolify中,您有一些有用的方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Rails中动态在Concern中定义实例方法 - Define instance methods in Concern dynamically on Rails 访问类属性以在 rails 问题中定义实例方法 - Accessing class property to define instance methods in rails concern Rails:使用模型中的常量将实例方法定义为Concern - Rails: Use constants from model for define instance methods into Concern Ruby / Rails 元编程,如何动态定义实例和 class 方法? - Ruby / Rails meta programing, how to define instance and class methods dynamically? 如何在模块中动态定义类的所有实例方法? - How to dynamically define all instance methods of class in module? 从实例方法中访问ActiveSupport :: Concern类方法 - Accessing ActiveSupport::Concern class methods from within instance methods ActiveSupport ::关注和类方法 - ActiveSupport::Concern and class methods 在 Rails 中动态定义类方法 - Define class methods dynamically in Rails 使用ActiveSupport :: Concern功能时,如何通过包括“嵌套”模块作为该类的实例方法来使添加到类中的方法成为现实? - How to make methods added to a class by including “nested” modules to be instance methods of that class when using the ActiveSupport::Concern feature? Rails:根据模块/关注内的父类名动态定义类方法 - Rails: dynamically define class method based on parent class name within module/concern
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM