开发者

method_missing override is not working

开发者 https://www.devze.com 2023-01-10 07:39 出处:网络
I wrote a convenience ActiveRecord extension to delegate methods to a base object (based on multi-table inheritance)

I wrote a convenience ActiveRecord extension to delegate methods to a base object (based on multi-table inheritance)

class ActiveRecord::Base
  def self.acts_as(base)
    class_eval %Q{
      def method_missing(method, *args, &blk)
        #{base}.send(method, *args, &blk)
      rescue NoMethodError
        super
      end
    }
  end
end

I have a state class and a base class

# state class
class MyState < ActiveRecord::Base
  belongs_to :my_object
  acts_as :my_object
end

# base class
class MyObject < ActiveRecord::Base
  has_one :head, :class_name => 'MyState'
  has_one :t开发者_StackOverflow中文版ail, :class_name => 'MyState'
end

When I tried this out, I found out that it doesn't work in some cases. More specifically,

> MyState.first.some_method_in_base
nil
> MyObject.first.tail.some_method_in_base
NoMethodError: undefined method `some_method_in_base' for #<ActiveRecord::Associations::HasOneAssociation:0xABCDEFG>

Can anyone enlighten me as to why one works and the other doesn't?


When you run MyObject.first.tail the object that actually responds is an AssociationProxy class that

has most of the basic instance methods removed, and delegates # unknown methods to @target via method_missing

You can get more details about the proxy running:

MyObject.first.proxy_owner
MyObject.first.proxy_reflection
MyObject.first.proxy_target

If you look in the code, you can see that the AssociationProxy proxies the method some_method_in_base to your MyState class only if MyState responds to some_method_in_base as you can see in the code below.

  private
    # Forwards any missing method call to the \target.
    def method_missing(method, *args, &block)
      if load_target
        if @target.respond_to?(method)
          @target.send(method, *args, &block)
        else
          super
        end
      end
    end

Therefore, the method_missing you have defined in the target class is never called.

0

精彩评论

暂无评论...
验证码 换一张
取 消