Hi --
I've been using has_many for quite a while now and thought I understood
it fairly well (I'm on Edge Rails).
But I've come across some unexpected behaviour, and I wonder if anyone
could shed some light on it.
If I assign a collection to a variable seems to change as the collection
changes. IS that expected?
Quick example
Let's say:
human has_many :cats
cat belongs_to :human
and in this example bob is a Human with id 2 with 1 cat
bob = Human.find(2)
bobs_cats = bob.cats
bobs_cats.size #=> 1
bob.cats.create(:name => "Tibbles")
bobs_cats.size #=> 2
So, the variable bob_cats is changing as the collection changes.
However if I replace the second line with bobs_cats =
bob.cats.find(:all) it behaves I would expect, i.e. behaves as an array
of Cat objects, and is not affected by changes to the collection.
Can anyone shed any light on this?
yes, they are the same because of this line
bobs_cats = bob.cats
they are the same instance. check the objects id's and you will see
bob.cats.object_id
=> 18829402
bobs_cats.object_id
=> 18829402
you should see something similar.
if you want a separate object, use .dup for duplicate
bobs_cats = bob.cats.dup
bobs_cats.object_id
=> 19619092
bob.cats.object_id
=> 18829402
now there are two distinct objects
Just to elaborate a little further: this is happening because the
object in question is an association proxy object. It gets created
the first time, and then cached:
=> #<Tag:0xb75f6d1c @attributes={"body"=>"Device", "id"=>"1"}>
things = tag.things
=> <things not loaded yet> # (Ugh, but that's another story 
things.object_id
=> -609253418
tag.things.object_id
=> -609253418
And when you call tag.things again, you get the same object:
tag.things.object_id
=> -609253418
It gets a little weirder here:
tag.things.reload
=> [#<Thing:0xb75e99dc @readonly=true, @attributes={"thing_id"=>"4",
"tag_id"=>"1", "id"=>"4"}>, #<Thing:0xb75e99c8 @readonly=true,
@attributes={"thing_id"=>"1", "tag_id"=>"1", "id"=>"21"}>,
#<Thing:0xb75e99a0 @readonly=true, @attributes={"thing_id"=>"2",
"tag_id"=>"1", "id"=>"22"}>]
tag.things.object_id
=> -609268288
things.object_id
=> -609268288
The object_id of things has changed, though things has not been
reassigned. Rather bizarre from the Ruby point of view, and not
particularly to my taste; I prefer to know what's going to happen when
I assign to a variable, and to be the one who decides if and when the
binding will change. But it's unlikely to cause trouble in practice,
as far as I can tell.
David