# ActiveRecord Comparison Bug?

**URL:** <https://www.ruby-forum.com/t/activerecord-comparison-bug/165112>\
**Category:** Rails\
**Created:** [April 9, 2009, 8:58am UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112 "2009-04-09T08:58:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 9, 2009, 8:58am UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/1 "2009-04-09T08:58:58Z")

</div>

Hi Everyone,

I’m running into a problem with the ActiveRecord::Base “==” method  
defined here (it’s 2.3.2, but it looks the same in older versions  
too):

```
  # File rails-2.3.2/activerecord/lib/active_record/base.rb, line

```

2816  
2816: def ==(comparison\_object)  
2817: comparison\_object.equal?(self) ||  
2818: (comparison\_object.instance\_of?(self.class) &&  
2819: comparison\_object.id == id &&  
2820: !comparison\_object.new\_record?)  
2821: end

Because of the last criteria (!comparison\_object.new\_record?),  
something like this happens… say i have a new record and an existing  
record (different objects) and compare them:

> new == old  
> =\> true  
> old == new  
> =\> false

If this is intentional, can someone please explain why this is?

Also what is the rational of only comparing the ID and not the all the  
values too and why does it matter if it’s a new record or not?

Thank you!  
-Moo

---

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 10, 2009, 6:51pm UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/2 "2009-04-10T18:51:31Z")

</div>

Anyone has any thoughts on this please?

---

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 10, 2009, 7:53pm UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/3 "2009-04-10T19:53:00Z")

</div>

On Apr 10, 5:50 pm, Moo [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Anyone has any thoughts on this please?

Basically the rationale is that == should mean ‘do these objects  
correspond to the same database row ?’

The reason why unsaved records are special cased is that two unsaved  
record would have equal id (nil in both cases) but if you saved them  
you would end up with 2 distinct rows in your database.

I’m not sure why you’re getting new ==old not being the same as old  
== new. They should both be false (and are on my machine)

Fred

---

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 16, 2009, 2:38am UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/4 "2009-04-16T02:38:38Z")

</div>

Hi Fred,

Thank you for the response! What you said made sense. thanks for the  
explanation.

However, looking at the last criteria of the == implementation, we can  
see why something like what i mentioned would fail:

let’s say i have an 2 AR objects:

> old = Something.find(1)  
> =\> #\<Something id: 1\>

then i create a new object:

> new = Something.new  
> =\> #  
> new.id = 1 # something like this is possible, how or why is another story…  
> new  
> =\> #\<Something id: 1\>

now do:

> new == old  
> =\> true  
> old == new  
> =\> false

== method should be commutative, right?

appreciate any comments!  
-Moo

On Apr 10, 10:52 am, Frederick C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 16, 2009, 5:18am UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/5 "2009-04-16T05:18:01Z")

</div>

> =\> #\<Something id: 1\>
> 
> > new == old  
> > =\> true  
> > old == new  
> > =\> false
> 
> == method should be commutative, right?

You’ve got something screwy somewhere…

old = Toy.fin\>\> old = Toy.find(1)  
=\> #\<BabyToy id: 1, …\>

> > new = Toy.new  
> > =\> #\<Toy id: nil, …\>
> 
> > new.id = 1  
> > =\> 1
> 
> > old == new  
> > =\> false
> 
> > new == old  
> > =\> false

Rails 2.3.2.1

-philip

---

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 16, 2009, 9:55am UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/6 "2009-04-16T09:55:27Z")

</div>

On Apr 16, 4:17 am, Philip H. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> You’ve got something screwy somewhere…

Your case is different because of STI (so your comparisons here are  
all false because the objects are of different class). If it weren’t  
for that then it’s a slightly messed up situation - Active record  
thinks it has a new record but it doesn’t

Fred

---

<div class="post-metadata">

**Author:** ![moo](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@moo](https://www.ruby-forum.com/u/moo)\
**Post date:** [April 16, 2009, 7:12pm UTC](https://www.ruby-forum.com/t/activerecord-comparison-bug/165112/7 "2009-04-16T19:12:00Z")

</div>

> Your case is different because of STI (so your comparisons here are  
> all false because the objects are of different class). If it weren’t  
> for that then it’s a slightly messed up situation - Active record  
> thinks it has a new record but it doesn’t

Doh! Didn’t catch that. And when I do it without involving STI then  
I get the results he’s getting below. Sorry Moo!

Hrm… well down in AR::Base we have this:

```
   # Returns true if the +comparison_object+ is the same object,

```

or is of the same type and has the same id.  
def ==(comparison\_object)  
comparison\_object.equal?(self) ||  
(comparison\_object.instance\_of?(self.class) &&  
comparison\_object.id == id &&  
!comparison\_object.new\_record?)  
end

Which interestingly enough matches each of the conditions the parent  
posted about.

I guess what this means then is if you’re mucking around setting the  
id’s of a record and before they are saved you should call equal?  
directly.

> > old = AdminUser.find(1)  
> > =\> #\<AdminUser id: 1…\>
> 
> > new = AdminUser.new  
> > =\> #
> 
> > new.id = 1  
> > =\> 1
> 
> > old == new  
> > =\> false
> 
> > new == old  
> > =\> true
> 
> > old.equal?(new)  
> > =\> false
> 
> > new.equal?(old)  
> > =\> false
