ruby-on-railsruby-on-rails-3method-missing

Define class methods dynamically in Rails


I define class methods dynamically in Rails as follows:

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

How can I use method missing to call find_by_SOME_SCHOOL_id without having to predefine these schools in %w[school1 school2]?


Solution

  • It is not completely clear to me what you want to achieve. If you want to call a method, you naturally have to define it first (as long as ActiveRecord does not handle this). You could do something like this:

    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
    

    This will output:

    1
    2
    22
    nil
    

    You could then do something with the ID contained in the method name. If you are sure that the method is defined, you can also use send(m, args) to call that method on an object/class. Beware though, if you do that on the same class that receives the method missing call and the method is not defined, you will get a stack overflow.