Method_missing override not working

I wrote a convenient ActiveRecord extension for delegating methods to a base object (based on the inheritance of multiple tables )

  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: tail,: class_name => 'MyState'
 end

When I tried this, I found out that in some cases this does not work. More specific,

  > 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 someone enlighten me why it works and the other does not?

+4
source share
1 answer

When running MyObject.first.tail object that actually responds is the AssociationProxy class, which

removed most basic instance methods, and # unknown method delegates for @target via method_missing

You can get more detailed information about the proxy server:

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

If you look in the code, you will see that AssociationProxy proxies the some_method_in_base method to the 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 that you defined in the target class is never called.

+5
source

All Articles