How do rails association methods work?

后端 未结 4 629
自闭症患者
自闭症患者 2020-11-29 04:29

How do rails association methods work? Lets consider this example

class User < ActiveRecord::Base
   has_many :articles
end

class Article < ActiveReco         


        
4条回答
  •  执念已碎
    2020-11-29 04:47

    How it actually works is that the association object is a "proxy object". The specific class is AssociationProxy. If you look at line 52 of that file, you'll see:

    instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
    

    By doing this, methods like class no longer exist on this object. So if you call class on this object, you'll get method missing. So, there a method_missing implemented for the proxy object that forwards the method call to the "target":

    def method_missing(method, *args)
      if load_target
        unless @target.respond_to?(method)
          message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}"
          raise NoMethodError, message
        end
    
        if block_given?
          @target.send(method, *args)  { |*block_args| yield(*block_args) }
        else
          @target.send(method, *args)
        end
      end
    end
    

    The target is an Array, so when you call class on this object, it says it's an Array, but that's just because the target is an Array, the actual class is an AssociationProxy, but you can't see that anymore.

    So all the methods that you add, such as of_sector, get added to the association proxy, so they get called directly. Methods like [] and class aren't defined on the association proxy, so they get sent to the target, which is an array.

    To help you see how this is happening, add this to line 217 of that file in your local copy of association_proxy.rb:

    Rails.logger.info "AssociationProxy forwarding call to `#{method.to_s}' method to \"#{@target}\":#{@target.class.to_s}" 
    

    If you don't know where that file is, the command gem which 'active_record/associations/association_proxy' will tell you. Now when you call class on a AssociationProxy, you will see a log message telling you it is sending that to the target, which should make it clearer what is happening. This is all for Rails 2.3.2 and could change in other versions.

提交回复
热议问题