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]