rails 关联方法如何工作? [英] How do rails association methods work?

查看:27
本文介绍了rails 关联方法如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

rails 关联方法是如何工作的?让我们考虑这个例子

How do rails association methods work? Lets consider this example

class User < ActiveRecord::Base
   has_many :articles
end

class Article < ActiveRecord::Base
   belongs_to :user
end

现在我可以做类似的事情

Now I can do something like

@user = User.find(:first)
@user.articles

这会为我获取属于该用户的文章.到目前为止一切顺利.

This fetches me articles belonging to that user. So far so good.

现在,我可以继续在某些条件下对这些文章进行查找.

Now further I can go ahead and do a find on these articles with some conditions.

@user.articles.find(:all, :conditions => {:sector_id => 3})

或者简单地声明和关联方法如

Or simply declare and associations method like

class User < ActiveRecord::Base
   has_many :articles do
     def of_sector(sector_id)
       find(:all, :conditions => {:sector_id => sector_id})
     end
   end
end

@user.articles.of_sector(3)

现在我的问题是,这个 find 如何在使用关联方法获取的 ActiveRecord 对象数组上工作?因为如果我们实现我们自己的名为 articlesUser 实例方法,并编写我们自己的实现,该方法为我们提供与关联方法完全相同的结果,fetch 数组上的 findActiveRecord 对象将无法工作.

Now my question is, how does this find work on the array of ActiveRecord objects fetched using the association method? Because if we implement our own User instance method called articles and write our own implementation that gives us the exact same results as that of the association method, the find on the fetch array of ActiveRecord objects wont work.

我的猜测是关联方法将某些属性附加到获取的对象数组,以便使用 find 和其他 ActiveRecord 方法进行进一步查询.在这种情况下,代码执行的顺序是什么?我如何验证这一点?

My guess is that the association methods attach certain properties to the array of fetched objects that enables further querying using find and other ActiveRecord methods. What is the sequence of code execution in this this case? How could I validate this?

推荐答案

它的实际工作原理是关联对象是一个代理对象".具体的类是AssociationProxy.如果您查看该文件的第 52 行,您会看到:

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$)/ }

通过这样做,像 class 这样的方法不再存在于这个对象上.所以如果你在这个对象上调用 class ,你会丢失方法.因此,为将方法调用转发到目标"的代理对象实现了一个 method_missing:

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

目标是一个数组,所以当你在这个对象上调用class时,它说它是一个数组,但这只是因为目标是一个数组,实际的类是一个AssociationProxy,但是你再也看不到了.

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.

因此,您添加的所有方法,例如 of_sector,都会添加到关联代理中,因此它们会被直接调用.[]class 之类的方法没有在关联代理上定义,所以它们被发送到目标,这是一个数组.

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.

为了帮助您了解这是如何发生的,请将其添加到该文件的本地副本 association_proxy.rb 中的第 217 行:

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}" 

如果你不知道那个文件在哪里,命令 gem which 'active_record/associations/association_proxy' 会告诉你.现在,当您在 AssociationProxy 上调用 class 时,您将看到一条日志消息,告诉您它正在将其发送到目标,这应该更清楚发生了什么.这是 Rails 2.3.2 的全部内容,可能会在其他版本中更改.

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.

这篇关于rails 关联方法如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆