This project is archived and is in readonly mode.

#3120 ✓resolved
fritz

ActiveRecord::Base#== is non-commutative when comparing a loaded versus initialized object

Reported by fritz | August 31st, 2009 @ 07:02 AM

If you compare a fully loaded model object with an initialized object of the same type and with the same id, the result of the == operator depends on order of operands. For example:

>> loaded_object = MyModel.last
=> #< MyModel id: 842437485, user_id: 11, ...>
>> initialized_object = MyModel.new
=> #< MyModel id: nil, user_id: nil, ...>
>> initialized_object.id = loaded_object.id
=> 842437485
>> initialized_object == loaded_object
=> true
>> loaded_object == initialized_object   # (!)
**=> false**

It's clear from the implementation why this is the case:

2811:       def ==(comparison_object)
2812:         comparison_object.equal?(self) ||
2813:           (comparison_object.instance_of?(self.class) &&
2814:             comparison_object.id == id &&
2815:             ***!comparison_object.new_record?***)
2816:       end

I can't imagine that the intent was a non-commutative equality operator.

This could be resolved either by ensuring that new records either never or always compare equal to records with the same id. However I'm not sure what the intent is. My instinct is "always" (i.e., removing the "&& !comparison_object.new_record?"), but I'm not totally sure of the intent.

I'm happy to submit a patch and the requisite tests if I can get some input on which way the fix should go...

Comments and changes to this ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

People watching this ticket

Pages