鉴于来自Foo
的名为ActiveRecord
的集合,为什么Array#include?
似乎不会调用Foo.==
但index
呢?
class Foo < ActiveRecord::Base
def ==(s)
self.name == s
end
end
class Bar < ActiveRecord::Base
has_many :foos
end
bar.foos << Foo.new( :name => 'hmm' )
bar.foos.all.include?('hmm') # does select all from db every time
=> true
bar.foos.include?('hmm') # does not go to db, but does not find the Foo!
=> false
bar.foos.index('hmm') # does not go to db, but does find the Foo[0] !
=> 0
bar.foos.index('eh') # no such object
=> nil
我对代理人的理解很浅,但是(没有绕过AR源代码)为什么索引似乎表现正确但包括?不是!?
这是代理行为中的错误,和/或是否在某处记录了此行为?
感谢。
答案 0 :(得分:0)
这是因为bar.foos
未返回ActiveRecord::Base
个对象,但返回AssociationProxy
(请参阅association_proxy.rb
)。
我建议您不要在关联代理中重新定义==
,否则您将改变应用程序中所有关联的行为。
答案 1 :(得分:0)
这提示我虽然阅读文档,但association_proxy.rb
的源代码(实际上,AssociationCollection
模拟了关联返回的集合上的Array方法。)
查看AssociationCollection.include?
File activerecord/lib/active_record/associations/association_collection.rb, line 332
def include?(record)
return false unless record.is_a?(@reflection.klass)
load_target if @reflection.options[:finder_sql] && !loaded?
return @target.include?(record) if loaded?
exists?(record)
end
看起来arg record
应该是@reflection.klass
类型,而Array.include?
看一个对象并使用在数组对象上定义的==
比较器。 / p>
嗯,这不是我想要的AR。既然是Enumerable.member?似乎在协会集合上工作,我只会使用它。我想扫描缓存的集合,而不是再次访问数据库。也许有人可以解释AssociationCollection如何重新映射成员? ?