# Tertiary has\_many association forms, difficult! (SOLUTION)

**URL:** <https://www.ruby-forum.com/t/tertiary-has-many-association-forms-difficult-solution/147612>\
**Category:** Rails\
**Created:** [September 3, 2008, 5:06pm UTC](https://www.ruby-forum.com/t/tertiary-has-many-association-forms-difficult-solution/147612 "2008-09-03T17:06:03Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![matthew](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/ed655f/32.png) [@matthew](https://www.ruby-forum.com/u/matthew)\
**Post date:** [September 3, 2008, 5:06pm UTC](https://www.ruby-forum.com/t/tertiary-has-many-association-forms-difficult-solution/147612/1 "2008-09-03T17:06:03Z")

</div>

I’ve got three relationships:

Package, PackageItemGroup, and PackageItem

[Package] has\_many :package\_item\_groups,  
has\_many :package\_items, :through =\> :package\_item\_groups  
[PackageItemGroup] has\_many :package\_items, belongs\_to :package

Ok, I need a form that will build params like this upon submit

:package =\> {  
:name =\> “Package Name”,  
:package\_item\_groups =\> [  
{:package\_items =\> [{:item\_id =\> “2”}, {:item\_id =\> “3”}]},  
{:package\_items =\> [{:item\_id =\> “4”}, {:item\_id =\> “5”}]}  
]  
}

Using fields for on package\_item\_groups with a form name like  
“package[package\_item\_groups][]” works fine. The params returned from  
that look ok. It’s when you try and add the third level of  
association with package\_items fields\_for, becuase  
“package[package\_item\_groups][][package\_items][]” does not work, as it  
is a completely invalid array.

Here is what I did to get params that I could use, I created a  
counter, that would serve as an index for the package\_item\_groups  
array. This counter would create key values that didn’t mean  
anything, aside from the form associating the correct package\_items  
and package\_item\_groups together.

This is an example:  
\<% fields\_for “package[package\_item\_groups][]”,  
PackageItemGroup.new, :index =\> Counter.index %\>

Counter.index being a integer value that I can store in session, keep  
track of, and increment / decrement when needed.

This solution WORKS, but it SUCKS. It’s very ugly, and essentially a  
hack. Also, the above solution is only for the new form, the edit  
form has to be different, which makes it a pain in the neck to  
maintain.

Has anyone else tried this before? Any luck with a more elegant  
solution that mine? I’ve googled, but had a very difficult time  
finding people in the same boat, perhaps this is just too much to  
expect from a simple web application, I dunno. Some comments would be  
very welcome and helpful.

---

<div class="post-metadata">

**Author:** ![matthew](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/ed655f/32.png) [@matthew](https://www.ruby-forum.com/u/matthew)\
**Post date:** [September 3, 2008, 5:48pm UTC](https://www.ruby-forum.com/t/tertiary-has-many-association-forms-difficult-solution/147612/2 "2008-09-03T17:48:24Z")

</div>

Matt S. wrote:

> :package =\> {  
> association with package\_items fields\_for, becuase  
> \<% fields\_for “package[package\_item\_groups][]”,  
> Has anyone else tried this before? Any luck with a more elegant  
> solution that mine? I’ve googled, but had a very difficult time  
> finding people in the same boat, perhaps this is just too much to  
> expect from a simple web application, I dunno. Some comments would be  
> very welcome and helpful.

In my experience, the way you’ve done it is essentially  
the best way.

But it can be made to work for both new and old records  
simultaneously. You use record ids as the index, and set  
the ids of new records to a negative value sequence in  
your controller or model. You can then identify which  
params correspond to new records.

–  
Rails Wheels - Find Plugins, List & Sell Plugins -  
[http://railswheels.com](http://railswheels.com)

---

<div class="post-metadata">

**Author:** ![matthew](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/ed655f/32.png) [@matthew](https://www.ruby-forum.com/u/matthew)\
**Post date:** [September 3, 2008, 7:59pm UTC](https://www.ruby-forum.com/t/tertiary-has-many-association-forms-difficult-solution/147612/3 "2008-09-03T19:59:52Z")

</div>

That sounds like a better solution than using a cached counter index.  
Would you mind explaining the “negative value sequence” a little more?

I’m guessing that you are talking about overwriting the id methods so  
that if the object is new\_record? true, then it would product a number  
in it’s place.

Also, right now I am messing around with having some params have a  
new\_ or existing\_ prefix, but that is turning out to be nightmarish.  
It would be much simpler if they didn’t have a prefix, and my custom  
setter methods (ie. package\_item\_groups=() ) could figure out if the  
incoming was to be created or updated.

On Sep 3, 11:45 am, Mark Reginald J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![matthew](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/ed655f/32.png) [@matthew](https://www.ruby-forum.com/u/matthew)\
**Post date:** [September 3, 2008, 10:35pm UTC](https://www.ruby-forum.com/t/tertiary-has-many-association-forms-difficult-solution/147612/4 "2008-09-03T22:35:20Z")

</div>

Matt S. wrote:

> That sounds like a better solution than using a cached counter index.  
> Would you mind explaining the “negative value sequence” a little more?
> 
> I’m guessing that you are talking about overwriting the id methods so  
> that if the object is new\_record? true, then it would product a number  
> in it’s place.

You just set the ids of any new records you create during a  
page render to -1, -2, -3, … These then go out to the form  
helpers and automatically receive these parameter indices,  
just as existing records receive positive indices when the  
auto-index “[]” notation is used.

> Also, right now I am messing around with having some params have a  
> new\_ or existing\_ prefix, but that is turning out to be nightmarish.  
> It would be much simpler if they didn’t have a prefix, and my custom  
> setter methods (ie. package\_item\_groups=() ) could figure out if the  
> incoming was to be created or updated.

Negative vs. positive does the job.

–  
Rails Wheels - Find Plugins, List & Sell Plugins -  
[http://railswheels.com](http://railswheels.com)
