在此处collection_association.rb
#has_many calls this eventually
def build
wrap_block_extension
...
end
接着
#here model refers to you model
#block_extension is the block you write with in the has_many definition(def foo blah blah)
def wrap_block_extension
...
model.parent.const_set(extension_module_name, Module.new(&block_extension))
options[:extend].push("#{model.parent}::#{extension_module_name}".constantize)
end
def extension_module_name
@extension_module_name ||= "#{model.to_s.demodulize}#{name.to_s.camelize}AssociationExtension"
end
我没有仔细阅读源代码,但我认为我们可以从这里得到一个有根据的猜测:b.items
返回一个对象(我忘记了类名,一些代理或其他东西,对不起),当方法丢失时,它会看起来到其他地方,包括options[:extend]
,所以在这种情况下,它给了我们我们想要的东西b.items.foo
。
但是当你调用 时b.items.bar
,它不会找到任何相关的东西,所以它会首先检查b.items
Array 的“返回值”是否响应 method #bar
,如果仍然没有,它会要求Item#bar
最后一次尝试。
在你的情况下,#delay
是一种被 识别的方法Array
,所以它真的很像tmp1 = b.items.all; tmp2 = tmp1.delay; tmp2.foo
,所以foo
肯定是无处可寻。