Model: self is not child's parent

Assume a model Parent and another model Child. Child belongs_to Parent
and Parent has_many Children. The following fails:

@
p = Parent.find(:first)
assert p.equal?(p.children[0].parent)
@

It seems odd to me that I and my child’s parent are not the same object.
In fact, this is royally screwing me up. Can anyone tell me why this is
or point me at a relevant discussion, blog posting, or bug that refers
to this.

Thanks!
-Ben

Ignore the spurious at-signs

On 18/05/2007, at 6:12 AM, Ben H. wrote:

object.
In fact, this is royally screwing me up. Can anyone tell me why
this is
or point me at a relevant discussion, blog posting, or bug that refers
to this.

ActiveRecord (at least in Rails 1.2.3) doesn’t do object caching, so
following the relationships down and back up again will give you a
new object. However:

 assert p == p.children[0].parent

should still succeed.

Pete Y.

a.equal?(b) iff a is the same object as b

The eql? method returns true if obj and anObject have the same value

On 5/17/07, Pete Y. [email protected] wrote:

assert p.equal?(p.children[0].parent)
following the relationships down and back up again will give you a


Amos K.
Ramped Media
USPS
Programmer/Analyst
St. Louis, MO
Looking for something to do? Visit ImThere.com

Seems to work perfectly for me.

parent.rb
class Parent < ActiveRecord::Base
has_many :children
end

child.rb
class Child < ActiveRecord::Base
belongs_to :parent
end

parent_test.rb
def test_child_parent_is_parent
parent = Parent.find(:first)
assert_equal parent, parent.children[0].parent
end

003_load_test_data.rb
class LoadTestData < ActiveRecord::Migration
def self.up
parent = Parent.create(:name => “Robert”)
Child.create(:name => “Bill”, :parent => parent)
Child.create(:name => “Sally”, :parent => parent)
end

def self.down
Child.delete_all
Parent.delete_all
end
end

Test results:
Rigel$ ruby test/unit/parent_test.rb
Loaded suite test/unit/parent_test
Started
.
Finished in 0.10244 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

On May 17, 4:13 pm, Ben H. [email protected]

A bit more detail too offer…

From the ri on equal?:


Object#equal?
obj == other => true or false
obj.equal?(other) => true or false
obj.eql?(other) => true or false

 Equality---At the +Object+ level, +==+ returns +true+ only if

obj
and other are the same object. Typically, this method is
overridden in descendent classes to provide class-specific
meaning.

 Unlike +==+, the +equal?+ method should never be overridden by
 subclasses: it is used to determine object identity (that is,
 +a.equal?(b)+ iff +a+ is the same object as +b+).

 The +eql?+ method returns +true+ if _obj_ and _anObject_ have the
 same value. Used by +Hash+ to test members for equality. For
 objects of class +Object+, +eql?+ is synonymous with +==+.
 Subclasses normally continue this tradition, but there are
 exceptions. +Numeric+ types, for example, perform type conversion
 across +==+, but not across +eql?+, so:

    1 == 1.0     #=> true
    1.eql? 1.0   #=> false

And both these assertions pass just fine:
def test_child_parent_is_parent
parent = Parent.find(:first)
assert_equal(parent, parent.children[0].parent)
assert(parent.eql?(parent.children[0].parent))
end

Thanks for answering my question. I suspected the complexity involved
in ensuring that self and child’s parent are not just the same database
row but also the same instance was prohibitive. Looks like I was right.

-Ben

But you are correct that this is two separate instances of the Parent
object. Rails does not seem to have a uniquing system so you’ll need
to compare object equality using methods supplied by ActiveRecord,
which is how “assert_equal” is going to determine equality.

Basically, you have two separate instances of Parent representing the
same row in the parents table. Building a system that ensures object
equality in object relational mapping is a pretty complex endeavor.
It appears that Rails makes no attempt to do this.

you want.

assert p.eql? not p.equal? (equal is more restrictive/exact than
eql?).

I’m not entirely sure, but I believe when you call
p.children[0].parent you are actually instantiating in memory an new
object of Parent class. So, #<Parent:0x39f3018 > is exactly equal to
#<Parent:0x39f3020 >

so in the end use == or eql? instead of equal? if your not wanting to
check for EXACTLY the same instance of Parent.

Hope that helps,
Jim

On May 17, 3:13 pm, Ben H. [email protected]