# Empty collection returned for model with has\_many relationship

**URL:** <https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981>\
**Category:** rubyonrails-talk\
**Created:** [January 6, 2009, 2:41am UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981 "2009-01-06T02:41:27Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![bigsley](https://avatars.discourse-cdn.com/v4/letter/b/5fc32e/32.png) [@bigsley](https://discuss.rubyonrails.org/u/bigsley)\
**Post date:** [January 6, 2009, 2:41am UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/1 "2009-01-06T02:41:27Z")

</div>

I have two models:

Exercise, and Step. Exercise has many steps.

Basically, when I add a step to a new exercise's "steps" array, it saves, and everything works. If I then get the exercise from the model (via find), clear its array, then add the step again, I cannot save the step to the exercise. Here is a console dump which shows exactly what happens:

---

<div class="post-metadata">

**Author:** ![Mark\_James](https://avatars.discourse-cdn.com/v4/letter/m/58f4c7/32.png) [@Mark\_James](https://discuss.rubyonrails.org/u/Mark_James)\
**Post date:** [January 6, 2009, 12:52pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/2 "2009-01-06T12:52:33Z")

</div>

bigsley wrote:

> I have two models:
> 
> Exercise, and Step. Exercise has many steps.
> 
> Basically, when I add a step to a new exercise's "steps" array, it saves, and everything works. If I then get the exercise from the model (via find), clear its array, then add the step again, I cannot save the step to the exercise. Here is a console dump which shows exactly what happens:
> 
> ----------
> 
> > > a = Exercise.new
> 
> =\> #\<Exercise id: nil, name: nil, description: nil, image: nil, created\_at: nil, updated\_at: nil\>
> 
> > > a.name = "The Name"
> 
> =\> "The Name"
> 
> > > b = Step.new
> 
> =\> #\<Step id: nil, description: nil, picture: nil, number: nil, exercise\_id: nil , created\_at: nil, updated\_at: nil, name: nil\>
> 
> > > c = Step.new
> 
> =\> #\<Step id: nil, description: nil, picture: nil, number: nil, exercise\_id: nil , created\_at: nil, updated\_at: nil, name: nil\>
> 
> > > a.save
> 
> =\> true
> 
> > > b.save
> 
> =\> true
> 
> > > c.save
> 
> =\> true
> 
> > > a.steps \<\< b
> 
> =\> [#\<Step id: 35, description: nil, picture: nil, number: nil, exercise\_id: 26, created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:38", name: nil
> 
> > ]
> 
> > > a.steps \<\< c
> 
> =\> [#\<Step id: 35, description: nil, picture: nil, number: nil, exercise\_id: 26, created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:38", name: nil
> 
> > , #\<Step id: 36, description: nil, picture: nil, number: nil, exercise\_id: 26,
> 
> created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:40", name: nil\> ]
> 
> > > a.save
> 
> =\> true
> 
> > > a = Exercise.find\_by\_name("The Name")
> 
> =\> #\<Exercise id: 26, name: "The Name", description: nil, image: nil, created\_at : "2009-01-06 02:26:35", updated\_at: "2009-01-06 02:26:35"\>
> 
> > > a.steps
> 
> =\> [#\<Step id: 35, description: nil, picture: nil, number: nil, exercise\_id: 26, created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:38", name: nil
> 
> > , #\<Step id: 36, description: nil, picture: nil, number: nil, exercise\_id: 26,
> 
> created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:40", name: nil\> ]
> 
> > > a.steps.clear()
> 
> =\>
> 
> > > a.steps \<\< b
> 
> =\> [#\<Step id: 35, description: nil, picture: nil, number: nil, exercise\_id: 26, created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:38", name: nil
> 
> > ]
> 
> > > a.steps \<\< c
> 
> =\> [#\<Step id: 35, description: nil, picture: nil, number: nil, exercise\_id: 26, created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:38", name: nil
> 
> > , #\<Step id: 36, description: nil, picture: nil, number: nil, exercise\_id: 26,
> 
> created\_at: "2009-01-06 02:26:36", updated\_at: "2009-01-06 02:26:40", name: nil\> ]
> 
> > > a.save
> 
> =\> true
> 
> > > b.save
> 
> =\> true
> 
> > > c.save
> 
> =\> true
> 
> > > a = Exercise.find\_by\_name("The Name")
> 
> =\> #\<Exercise id: 26, name: "The Name", description: nil, image: nil, created\_at : "2009-01-06 02:26:35", updated\_at: "2009-01-06 02:26:35"\>
> 
> > > a.steps
> 
> =\>
> 
> ----------
> 
> What is going on here? This is so anti-intuitive - how could a bug like this exist and not have been detected hundreds of times before?

Yes, I would regard this as a Rails bug. The clear method is not setting the foreign key to nil on the in-memory object.

It's only being manifest though because of the unnecessary saves you're doing, meaning that the problem has probably been rarely seen.

---

<div class="post-metadata">

**Author:** ![Mark\_James](https://avatars.discourse-cdn.com/v4/letter/m/58f4c7/32.png) [@Mark\_James](https://discuss.rubyonrails.org/u/Mark_James)\
**Post date:** [January 6, 2009, 1:02pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/3 "2009-01-06T13:02:36Z")

</div>

Mark Reginald James wrote:

I take this back:

> It's only being manifest though because of the unnecessary saves you're doing, meaning that the problem has probably been rarely seen.

The problem has been exposed by the new ActiveRecord change detection code.

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [January 6, 2009, 1:15pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/4 "2009-01-06T13:15:52Z")

</div>

> > ----------
> > 
> > What is going on here? This is so anti-intuitive - how could a bug like this exist and not have been detected hundreds of times before?
> 
> Yes, I would regard this as a Rails bug. The clear method is not setting the foreign key to nil on the in-memory object.

Even if it were setting it on the in memory object it wouldn't be in  
memory object you think it is. Because a was reloaded, the objects in  
a.steps are not the objects b & c (although they do correspond to the  
same database rows).

Fred

---

<div class="post-metadata">

**Author:** ![Mark\_James](https://avatars.discourse-cdn.com/v4/letter/m/58f4c7/32.png) [@Mark\_James](https://discuss.rubyonrails.org/u/Mark_James)\
**Post date:** [January 6, 2009, 2:21pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/5 "2009-01-06T14:21:44Z")

</div>

Frederick Cheung wrote:

> Even if it were setting it on the in memory object it wouldn't be in memory object you think it is. Because a was reloaded, the objects in a.steps are not the objects b & c (although they do correspond to the same database rows).

The problem happens before a is reloaded.

I just did some experiments with puzzling results. Would you be able to help explain them Fred?

Loading development environment (Rails 2.2.2) \>\> a = Exercise.find(1) =\> #\<Exercise id: 1\> \>\> b = Step.new =\> #\<Step id: nil, exercise\_id: nil\> \>\> b.save =\> true \>\> c = Step.new =\> #\<Step id: nil, exercise\_id: nil\> \>\> c.save =\> true \>\> a.steps \<\< b =\> [#\<Step id: 19, exercise\_id: 1\>] \>\> a.steps \<\< c =\> [#\<Step id: 19, exercise\_id: 1\>, #\<Step id: 20, exercise\_id: 1\>] \>\> b.object\_id =\> 70254505869500 \>\> a.steps.first.object\_id =\> 70254505813160 \>\> c.object\_id =\> 70254505838840 \>\> a.steps.last\_object\_id =\> 70254505838840

Why does only the first object in the collection have a different object\_id, and why does this difference go away if the empty a.steps is loaded before b is added? Is it a proxy thing?

I added a few lines to the has\_many code to set the foreign keys on the in-memory records to nil. But because of the above behaviour the fk doesn't change on the local variable that held the first element added to the collection, unless the collection had been pre-loaded.

---

<div class="post-metadata">

**Author:** ![11175](https://avatars.discourse-cdn.com/v4/letter/1/8edcca/32.png) [@11175](https://discuss.rubyonrails.org/u/11175)\
**Post date:** [January 6, 2009, 5:26pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/6 "2009-01-06T17:26:37Z")

</div>

Mark Reginald James wrote:

> Frederick Cheung wrote:
> 
> > Even if it were setting it on the in memory object it wouldn't be in  
> > memory object you think it is. Because a was reloaded, the objects in  
> > a.steps are not the objects b & c (although they do correspond to the  
> > same database rows).
> 
> The problem happens before a is reloaded.
> 
> I just did some experiments with puzzling results. Would you be able to help explain them Fred?
> 
> Loading development environment (Rails 2.2.2) \>\> a = Exercise.find(1) =\> #\<Exercise id: 1\> \>\> b = Step.new =\> #\<Step id: nil, exercise\_id: nil\> \>\> b.save =\> true \>\> c = Step.new =\> #\<Step id: nil, exercise\_id: nil\> \>\> c.save =\> true \>\> a.steps \<\< b =\> [#\<Step id: 19, exercise\_id: 1\>] \>\> a.steps \<\< c =\> [#\<Step id: 19, exercise\_id: 1\>, #\<Step id: 20, exercise\_id: 1\>] \>\> b.object\_id =\> 70254505869500 \>\> a.steps.first.object\_id =\> 70254505813160 \>\> c.object\_id =\> 70254505838840 \>\> a.steps.last\_object\_id =\> 70254505838840

Just a WAG, but a.steps.first.object\_id isn't the same reference method as a.steps.last\_object\_id

Is the first.object\_id creating a new reference to that object, whereas last\_object\_id is returning the reference present in a.steps?

Try the experiment again with the same object referencing method used for both first and last.

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [January 6, 2009, 5:32pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/7 "2009-01-06T17:32:26Z")

</div>

Because .first will hit the database and load a fresh copy (if the collection is not already loaded). I waffled about this a bit a while ago: [First, foremost and [0] - Space Vatican](http://www.spacevatican.org/2008/11/15/first-foremost-and-0)

Fred

---

<div class="post-metadata">

**Author:** ![bigsley](https://avatars.discourse-cdn.com/v4/letter/b/5fc32e/32.png) [@bigsley](https://discuss.rubyonrails.org/u/bigsley)\
**Post date:** [January 6, 2009, 7:40pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/8 "2009-01-06T19:40:17Z")

</div>

So is this a known bug? Is this fixed in 2.2.2? I'm currently running rails 2.1.1.

---

<div class="post-metadata">

**Author:** ![Mark\_James](https://avatars.discourse-cdn.com/v4/letter/m/58f4c7/32.png) [@Mark\_James](https://discuss.rubyonrails.org/u/Mark_James)\
**Post date:** [January 6, 2009, 10:20pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/9 "2009-01-06T22:20:41Z")

</div>

Frederick Cheung wrote:

> > Why does only the first object in the collection have a different object\_id, and why does this difference go away if the empty a.steps is loaded before b is added? Is it a proxy thing?
> 
> Because .first will hit the database and load a fresh copy (if the collection is not already loaded). I waffled about this a bit a while ago: [First, foremost and [0] - Space Vatican](http://www.spacevatican.org/2008/11/15/first-foremost-and-0)

Thanks Fred for pointing out the new behaviour of "first" and "last".

However that's not the problem here. You get the same behaviour if you use steps[0].

Looking at it again after some sleep, I see that the different b object is actually loaded at the "a.steps \<\< b" line. That is, the object is added by updating the foreign key in the database, loading the collection, then folding in any new\_records, which ends up giving you the different b from the database.

The association\_collection \<\< method could easily be changed to respect the identity of objects being added to a collection. Should this be done to respect the POLS, violated for the OP?

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [January 6, 2009, 11:51pm UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/10 "2009-01-06T23:51:39Z")

</div>

> The association\_collection \<\< method could easily be changed to respect the identity of objects being added to a collection. Should this be done to respect the POLS, violated for the OP?

Possibly. This area is fraught with subtleties though.

Fred

---

<div class="post-metadata">

**Author:** ![Mark\_James](https://avatars.discourse-cdn.com/v4/letter/m/58f4c7/32.png) [@Mark\_James](https://discuss.rubyonrails.org/u/Mark_James)\
**Post date:** [January 7, 2009, 11:59am UTC](https://discuss.rubyonrails.org/t/empty-collection-returned-for-model-with-has-many-relationship/37981/11 "2009-01-07T11:59:06Z")

</div>

bigsley wrote:

> So is this a known bug? Is this fixed in 2.2.2? I'm currently running rails 2.1.1.

The issue is present in 2.2.2, and probably edge. I'm looking into a fix, but as Fred says, there are several subtleties. I suggest you watch this ticket:

[http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1706](http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1706)

Assuming your console log was an attempt to investigate a problem with some real app code, you should be able to work around the problem by eliminating some unnecessary saves and some object reuse. You can post your real code if you like.
