# Catch-22 in association through join model

**URL:** <https://www.ruby-forum.com/t/catch-22-in-association-through-join-model/119227>\
**Category:** Rails\
**Created:** [November 5, 2007, 7:26am UTC](https://www.ruby-forum.com/t/catch-22-in-association-through-join-model/119227 "2007-11-05T07:26:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![eric99](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/a88e4f/32.png) [@eric99](https://www.ruby-forum.com/u/eric99)\
**Post date:** [November 5, 2007, 7:26am UTC](https://www.ruby-forum.com/t/catch-22-in-association-through-join-model/119227/1 "2007-11-05T07:26:08Z")

</div>

I have a many-to-many relationship defined by a join model:  
class Product \< ActiveRecord::Base  
has\_many :bundlings  
has\_many :bundles, :through =\> :bundlings  
…  
end

class Bundling \< ActiveRecord::Base  
belongs\_to :product  
belongs\_to :bundle  
…  
end

class Bundle \< ActiveRecord::Base  
has\_many :bundlings  
has\_many :products, :through =\> :bundlings  
…  
end

Additionally, _Bundle_ validates that it contains at least two products.

Then I tried to create a new _Bundle_ like this:

fixtures :products  
…

bundle = Bundle.new(…) # can’t save bundle yet since  
# I haven’t yet added two products  
bundle.products \<\< products(:product\_one)  
bundle.products \<\< products(:product\_two)  
bundle.save!

The “\<\<” operation raises an\*  
\*_ActiveRecord::HasManyThroughCantAssociateNewRecords  
exception, saying that both bundle and the product need to have an ID to  
use  
“\<\<” on a through association. However, in order to obtain an ID, I  
need to  
save bundle_, but _bundle_ cannot be saved (i.e. pass validation) unless  
I  
have added two products to it through “\<\<” – Catch 22.

Any thoughts?

Thanks,  
Eric

---

<div class="post-metadata">

**Author:** ![eric99](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/a88e4f/32.png) [@eric99](https://www.ruby-forum.com/u/eric99)\
**Post date:** [November 5, 2007, 6:04pm UTC](https://www.ruby-forum.com/t/catch-22-in-association-through-join-model/119227/2 "2007-11-05T18:04:33Z")

</div>

Eric L. wrote:

> I have a many-to-many relationship defined by a join model:  
> …  
> Additionally, _Bundle_ validates that it contains at least two products.
> 
> Then I tried to create a new _Bundle_ like this:
> 
> fixtures :products  
> …
> 
> bundle = Bundle.new(…) # can’t save bundle yet since  
> # I haven’t yet added two products  
> bundle.products \<\< products(:product\_one)  
> bundle.products \<\< products(:product\_two)  
> bundle.save!
> 
> The “\<\<” operation raises an\*  
> \*_ActiveRecord::HasManyThroughCantAssociateNewRecords  
> exception, saying that both bundle and the product need to have an ID to  
> use  
> “\<\<” on a through association. However, in order to obtain an ID, I  
> need to  
> save bundle_, but _bundle_ cannot be saved (i.e. pass validation) unless  
> I  
> have added two products to it through “\<\<” – Catch 22.

You can use a very simple state machine to control that the validation  
only runs when it’s ready. You’d create a bundle as unprepared, add the  
products, then save it as prepared.

–  
Josh S.  
[http://blog.hasmanythrough.com](http://blog.hasmanythrough.com)

---

<div class="post-metadata">

**Author:** ![eric99](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/a88e4f/32.png) [@eric99](https://www.ruby-forum.com/u/eric99)\
**Post date:** [November 5, 2007, 6:36pm UTC](https://www.ruby-forum.com/t/catch-22-in-association-through-join-model/119227/3 "2007-11-05T18:36:50Z")

</div>

Do you mean:

1. Create a unprepared bundled. Mark the unprepared status in one of  
its DB  
columns.
2. Save the unprepared bundle to DB to generate an ID for it
3. Add the products to the saved bundle.
4. When the second product is added, unmark the unprepared status in the  
DB  
column.

This seems like a good solution, even though it would bypass the  
validation  
mechanism of ActiveRecord, and has a little bit more maintenance of  
states…

Eric

---

<div class="post-metadata">

**Author:** ![eric99](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/a88e4f/32.png) [@eric99](https://www.ruby-forum.com/u/eric99)\
**Post date:** [November 5, 2007, 11:13pm UTC](https://www.ruby-forum.com/t/catch-22-in-association-through-join-model/119227/4 "2007-11-05T23:13:26Z")

</div>

Eric L. wrote:

> Do you mean:
> 
> 1. Create a unprepared bundled. Mark the unprepared status in one of  
> its DB  
> columns.
> 2. Save the unprepared bundle to DB to generate an ID for it
> 3. Add the products to the saved bundle.
> 4. When the second product is added, unmark the unprepared status in the  
> DB  
> column.
> 
> This seems like a good solution, even though it would bypass the  
> validation  
> mechanism of ActiveRecord, and has a little bit more maintenance of  
> states…

Yes, that’s what I mean. You don’t have to bypass validation though.  
You can include the condition of being prepared in the validation.  
Something like this:

def validate  
!prepared || products.size \>= 2  
end

–  
Josh S.  
[http://blog.hasmanythrough.com](http://blog.hasmanythrough.com)
