【问题标题】:Define class methods dynamically in Rails在 Rails 中动态定义类方法
【发布时间】:2013-06-24 18:16:00
【问题描述】:

我在 Rails 中动态定义类方法如下:

class << self
  %w[school1 school2].each do |school|
    define_method("self.find_by_#{school}_id") do |id|
        MyClass.find_by(school: school, id: id)
    end
  end
end

如何使用缺少的方法调用find_by_SOME_SCHOOL_id 而无需在%w[school1 school2] 中预先定义这些学校?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 method-missing


    【解决方案1】:

    我并不完全清楚你想要实现什么。如果要调用一个方法,自然要先定义它(只要 ActiveRecord 不处理这个)。你可以这样做:

    class MyClass
      class << self
        def method_missing(m, *args, &block)  
          match = m.to_s.match(/find_by_school([0-9]+)_id/)
          if match
            match.captures.first
          else
            nil
          end
        end  
      end
    end
    
    puts MyClass.find_by_school1_id
    puts MyClass.find_by_school2_id
    puts MyClass.find_by_school22_id
    puts MyClass.find_by_school_id
    

    这将输出:

    1
    2
    22
    nil
    

    然后您可以使用方法名称中包含的 ID 执行某些操作。如果您确定该方法已定义,您还可以使用send(m, args) 在对象/类上调用该方法。但请注意,如果您在接收方法缺失调用且方法未定义的同一个类上执行此操作,则会出现堆栈溢出。

    【讨论】:

    • 谢谢@mario。 Method_missing 是我正在寻找的。我想我需要解析 *arg 以动态生成与学校名称关联的方法,然后解析 *block 以将 ID 传递给这些方法。你能解释一下我会怎么做吗?
    • @AdamNYC 不完全是。你需要解析的是m参数。这包含被调用方法的名称,作为一个符号。在我的示例中,我使用正则表达式从方法名称中提取 ID。您当然可以使用defined? 检查该方法是否已经存在,然后使用define_method 和m 生成该方法(如果不存在)。
    【解决方案2】:

    除非你有匹配项,否则我建议返回 super

    
    class MyClass
      class << self
        def method_missing(m, *args, &block)  
          match = m.to_s.match(/find_by_school([0-9]+)_id/)
          match ? match.captures.first : super
        end  
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-20
      • 2017-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多