它实际上是如何工作的,关联对象是一个“代理对象”。具体班级是关联代理 http://github.com/rails/rails/blob/2-3-stable/activerecord/lib/active_record/associations/association_proxy.rb。如果您查看该文件的第 52 行,您将看到:
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
通过这样做,像这样的方法class
不再存在于该对象上。所以如果你打电话class
在此对象上,您将缺少方法。所以,有一个method_missing
为将方法调用转发到“目标”的代理对象实现:
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,但你再也看不到它了。
所以您添加的所有方法,例如of_sector
,被添加到关联代理中,因此它们会被直接调用。方法如[]
and class
未在关联代理上定义,因此它们被发送到目标(一个数组)。
为了帮助您了解这是如何发生的,请将以下内容添加到您的 Association_proxy.rb 本地副本中该文件的第 217 行:
Rails.logger.info "AssociationProxy forwarding call to `#{method.to_s}' method to \"#{@target}\":#{@target.class.to_s}"
如果您不知道该文件在哪里,请使用命令gem which 'active_record/associations/association_proxy'
会告诉你的。现在当你打电话时class
在 AssociationProxy 上,您将看到一条日志消息,告诉您它正在将其发送到目标,这应该可以让您更清楚地了解正在发生的情况。这全部适用于 Rails 2.3.2,在其他版本中可能会发生变化。