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? --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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 On 12/17/06, Chris T <ctmailinglists-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:> > 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? > > > > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
dblack-TKXtfPMJ4Ozk1uMJSBkQmQ@public.gmane.org
2006-Dec-17 19:40 UTC
Re: has_many: unexpected behaviour
Hi -- On Sun, 17 Dec 2006, Chris Hall wrote:> > On 12/17/06, Chris T <ctmailinglists-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: >> >> 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 objectsJust 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 -- Q. What''s a good holiday present for the serious Rails developer? A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black) aka The Ruby book for Rails developers! Q. Where can I get Ruby/Rails on-site training, consulting, coaching? A. Ruby Power and Light, LLC (http://www.rubypal.com) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
OK. That makes sense. Guess I never quite connected (in my mind) the Array of AR objects that is bob.cats and the bob.cats.create or whatever. I''m guess the additional has_many methods are available to the array through some sort of method_missing magic? Thanks for your help. Chris Chris Hall wrote:> 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 > > > On 12/17/06, Chris T <ctmailinglists-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: > >> 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? >> >> >> >> >> > > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
dblack-TKXtfPMJ4Ozk1uMJSBkQmQ@public.gmane.org wrote:> Hi -- > > On Sun, 17 Dec 2006, Chris Hall wrote: > > >> On 12/17/06, Chris T <ctmailinglists-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: >> >>> 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 > >David Thanks for this. Have been getting so much into the Ruby aspect of Rails recently (not least thanks to your excellent book) sort of forgot about some of the strange things that Rails does. Cheers Chris --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---