Array::include? on ActiveRecord collection not calling op==?
Given a collection of named Foo
s from ActiveRecord
, why does Array#include?
not seem to call Foo.==
but yet index
does?
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
I understand shallow about the proxies, but (without a detour into the AR source) why is index seemingly behaving correctly but include? is not !?
Is this a bug in the proxy behavior, 开发者_开发问答and/or is this behavior documented somewhere ?
Thanks.
This is because bar.foos
doesn't return an ActiveRecord::Base
object but returns an AssociationProxy
(see association_proxy.rb
).
I don't suggest you to redefine the ==
in the association proxy or you will alter the behavior for all your associations in your application.
Simone, that's not the answer I'm looking for (but I like the way you think ;-)
That prompts me though to read the documentation, er source code of association_proxy.rb
(actually, AssociationCollection
which emulates methods of Array on the collection returned by the association.)
Looking at 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
Looks like the arg record
is expected to be of type @reflection.klass
whereas Array.include?
takes an object and uses the ==
comparator defined on the objects of the array.
Well, this is not what I wanted from AR anyway. Since Enumerable.member? seems to work on the association collection, I'll just use that. I want to scan the cached collection, and not hit the database again. Maybe someone could explain how AssociationCollection is remapping member? ?
精彩评论