Search code examples
ruby-on-railsassociationsbelongs-tomethod-missing

Rails: method_missing is not called on model when using associations


My current code:

class Product < ActiveRecord::Base
  belongs_to :category
end

class Category < ActiveRecord::Base
  def method_missing name
    true
  end
end

Category.new.ex_undefined_method          #=> true
Product.last.category.ex_undefined_method #=> NoMethodError: undefined method `ex_undefined_method' for #<ActiveRecord::Associations::BelongsToAssociation:0xc4cd52c>

This happens because of this code in rails which only passes methods that exist to the model.

private
def method_missing(method, *args)
  if load_target
    if @target.respond_to?(method)
      if block_given?
        @target.send(method, *args)  { |*block_args| yield(*block_args) }
      else
        @target.send(method, *args)
      end
    else
      super
    end
  end
end

This is what I want:

Product.last.category.ex_undefined_method #=> true

How can I accomplish this?


Solution

  • Note that the AssociationProxy object only sends on methods that the target claims to respond_to?. Therefore, the fix here is to update respond_to? as well:

    class Category < ActiveRecord::Base
      def method_missing(name, *args, &block)
        if name =~ /^handleable/
          "Handled"
        else
          super
        end
      end
    
      def respond_to?(name)
        if name =~ /^handleable/
          true
        else
          super
        end
      end
    end
    

    In fact, you should always update respond_to? if you redefine method_missing - you've changed the interface of your class, so you need to make sure that everyone knows about it. See here.