ruby-on-railsrubymethod-missing

Calling method_missing for undefined attributes in Rails after using "update" method


Is there a short way for obj.update(attr1: "something") method to call method_missing instead of raising the error ActiveModel::UnknownAttributeError (unknown attribute 'attr1' for Obj.)?

I am thinking about simply rescuing it and then mimicking/calling the method_missing, but this way feels too bulky.


Solution

  • From the source code (Rails 4.2) it seems that ActiveRecord::UnknownAttributeError is raised when the model instance does not respond_to? to the given attribute setter. So what you have to do is define a method_missing as well as respond_to_missing? in the model for all your dynamic attributes. This is actually what you always should do when using method_missing anyway:

    class Model < ActiveRecord::Base
    
      DYNAMIC_ATTRIBUTES = [:attr1, :attr2]
    
      def method_missing(method_name, *arguments, &block)
        if DYNAMIC_ATTRIBUTES.map { |attr| "#{attr}=" }.include?(method_name.to_s)
          puts "custom code for #{method_name} #{arguments.first.inspect}"
        else
          super
        end
      end
    
      def respond_to_missing?(method_name, include_private = false)
        DYNAMIC_ATTRIBUTES.map { |attr| "#{attr}=" }.include?(method_name.to_s) || super
      end
    
    end
    

    Test in Rails console:

    Model.first.update(attr1: 'aa', attr2: 'bb')
    # => custom code for attr1= "aa"
    # => custom code for attr2= "bb"
    
    Model.first.update(attr1: 'aa', attr2: 'bb', attr3: 'cc')
    # => ActiveRecord::UnknownAttributeError: unknown attribute 'attr3' for Model.