开发者

Array::include? on ActiveRecord collection not calling op==?

Given a collection of named Foos 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? ?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜