# REST nested resources

**URL:** <https://discuss.rubyonrails.org/t/rest-nested-resources/32452>\
**Category:** rubyonrails-talk\
**Created:** [July 28, 2008, 11:21am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452 "2008-07-28T11:21:20Z")\
**Posts on this page:** 18\
**Page:** 1

<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:** [July 28, 2008, 11:21am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/1 "2008-07-28T11:21:20Z")

</div>

Hi

I'm porting an existing project to fit the REST philosofie. I have 3 resources that are nested: users, companies and roles. A user has and belongs to multiple companies, and depening on the company, a role will be assigned.

So I have an association table: users\_companies with the following fields: user\_id, company\_id, role\_id. But how do I assign a user to a company with a role the REST way?

Normally you would create a new controller, but I would like to do the assignments in the user form.

Anyone that has some experience on this?

Thank you in advance.

---

<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:** [July 28, 2008, 11:23am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/2 "2008-07-28T11:23:59Z")

</div>

Michael Rigart wrote:

> Hi
> 
> I'm porting an existing project to fit the REST philosofie. I have 3 resources that are nested: users, companies and roles. A user has and belongs to multiple companies, and depening on the company, a role will be assigned.
> 
> So I have an association table: users\_companies with the following fields: user\_id, company\_id, role\_id. But how do I assign a user to a company with a role the REST way?
> 
> Normally you would create a new controller, but I would like to do the assignments in the user form.
> 
> Anyone that has some experience on this?
> 
> Thank you in advance.

Sorry for adding this, but the association should also made possible on the company form.

---

<div class="post-metadata">

**Author:** ![Jeff1](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jeff1/32/1170_2.png) [@Jeff1](https://discuss.rubyonrails.org/u/Jeff1)\
**Post date:** [July 28, 2008, 2:29pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/3 "2008-07-28T14:29:23Z")

</div>

I thought I had an answer until I saw this addendum 🙂

Can you explain a little more what the company form is trying to do?

Jeff

---

<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:** [July 28, 2008, 2:51pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/4 "2008-07-28T14:51:55Z")

</div>

Jeff Cohen wrote:

> > Michael Rigart wrote:
> 
> > Sorry for adding this, but the association should also made possible on the company form.
> 
> I thought I had an answer until I saw this addendum 🙂
> 
> Can you explain a little more what the company form is trying to do?
> 
> Jeff

Sorry Jeff if I wasn't clear enough. The company and user form are basically used to create and / or edit a company or user.

Under the user details, there will be another "section" where the administrator can assign the companies to the user he is creating /editing with a sertain role.

On the other hand, when he is creating a new company, under the company details, there will be another "section" where the admin can assign users to the company he is creating / editing with a sertain role.

So its a litle complex and I can't see how to do this as restful as possible.

Thank you for your intereset.

---

<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:** [July 28, 2008, 7:47pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/5 "2008-07-28T19:47:39Z")

</div>

Anyone who has an idea this one?

---

<div class="post-metadata">

**Author:** ![Jeff1](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jeff1/32/1170_2.png) [@Jeff1](https://discuss.rubyonrails.org/u/Jeff1)\
**Post date:** [July 28, 2008, 9:42pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/6 "2008-07-28T21:42:00Z")

</div>

It sounds like you need to update multiple kinds of resources from one form, which unfortunately Rails doesn't handle very well yet (there are some proposed changes in edge that might help this, though).

I'd recommend posting to the controller that seems to represent the "main" resource (the user or company, as needed). I'm imagining you've got some checkboxes for users (or companies) that will come along for the ride.

That being the case, I would suggest that your create action (say, for users) pull out the company list from the params hash first:

# remove company IDs from the params hash # and keep the array of company IDs for later use # You might not need this step depending on # how your checkbox names are setup company\_ids = params[:user].delete :company

Now the params hash has just the user info remaining in it:

user = User.build(params[:user])

Now you can associate the user to the companies represented by the ids in one fell swoop:

user.company\_ids = company\_ids

Then save everything:

user.save # should save the relationships as well, I believe

Although it might seem "non-restful" to be assigning the company relationships from within the create action, I can't think of a better way to do it, and to me it actually seems reasonable. If the UI is specifying that creating a user includes assigning some associations, then I think it's legit to do this all within the create action.

What do you think?

Jeff

---

<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:** [August 5, 2008, 6:21pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/7 "2008-08-05T18:21:32Z")

</div>

Hi Jeff

sorry for the late reply, but I have come to some solution that fits my needs. But their are still some minor code details that need some upgrading becouse they can lead to errors due to possible wrong user input.

As you said, I send the data to the controller that represents the main resource (in the example I'm giving now that will be the company resource).

One thing that you need to know is that the related users table is build through Javascript. This is becouse you can add/delete more/less users dynamically. For that, I just create a simple table, and add the rules dynamically in the body. So on the end of the page, I do the following:

\<% @company.company\_roles.each do |role| %\> &nbsp;&nbsp;Company.addAssociatedUser(\<%= role.to\_json(:only =\> [:id, :user\_id, :role\_id]) %\>); \<% end %\>

The addAssociateUser mehthod adds the associations dynamicaly. On my form, I can add new rules by calling the method again, but without parameters.

So far, so good, that works. Now I submit my form, and all the data get send to the create/update action. To make it simple, I will show the create action:

&nbsp;&nbsp;def create &nbsp;&nbsp;&nbsp;&nbsp;@company = Company.new(params[:company])

&nbsp;&nbsp;&nbsp;&nbsp;if @company.save && save\_user\_role\_associations &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flash[:message] = l("company\_create\_response") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect\_to(companies\_url()) &nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render :action =\> "new" &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

So, I create my company object and save it. But, it also calls for a private action "save\_user\_role\_associations". This action looks like this:

&nbsp;&nbsp;def save\_user\_role\_associations &nbsp;&nbsp;&nbsp;&nbsp;saved\_ids =

&nbsp;&nbsp;&nbsp;&nbsp;params[:company\_user\_association].each do |key, item\_vals| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if item\_vals[:id].to\_i \> 0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association = CompanyRole.find(item\_vals[:id]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.update\_attributes(item\_vals) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association = CompanyRole.new(:company\_id =\> @company.id, :role\_id =\> item\_vals[:role\_id], :user\_id =\> item\_vals[:user\_id]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.save &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item\_vals.delete :id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saved\_ids \<\< association.id &nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;CompanyRole.find(:all, :conditions =\> ["company\_id = ? AND id NOT IN (?)",@company.id, saved\_ids]).each do |association| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.destroy &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

This all works, as long as the user input is correct. But lets state, that there is a wrong user input in the association data. This will reside in an application crash, becouse the error is not caught. The CompanyRole data doesn't get validated and displayed if an error occurs.

The second problem lies in the create method.

@company.save && save\_user\_role\_associations

Here the @company gets save, even if their is an error in the save\_user\_role\_associations action. How can I handle this?

Then another question (well, 2 question that relate to the same problem). Lets say I have related models that I need to use. Like a company can have a role. The roles are shown in a select, but ofcourse we need to load the resources before we can fill them. What I do now is create a private action in my controller that pulls all related resources that are needed.

&nbsp;&nbsp;def relational\_models &nbsp;&nbsp;&nbsp;&nbsp;@roles = Role.find(:all) &nbsp;&nbsp;end

So, for those resources to be available in the view, I call the relational\_models action in my new / edit action. That works like a charm. But, the problem occurs when there is an error on the form submit. As you can see in my above example, I redirect to the new action. But then the related resources don't get loaded again, and that resides in an application crash. How can I make sure, the related resources are loaded again properly? The 2nd question relates to this problem. I always load custom css/javascripts dynamically. So only when they are needed. I group my javascript per controller. So in overwrite the initialize action in my controller:

&nbsp;&nbsp;def initialize &nbsp;&nbsp;&nbsp;&nbsp;super

&nbsp;&nbsp;&nbsp;&nbsp;add\_styles\_and\_scripts &nbsp;&nbsp;end

The add\_styles\_and\_scripts action is again, a private action in my controller and can look like this:

&nbsp;&nbsp;def add\_styles\_and\_scripts &nbsp;&nbsp;&nbsp;&nbsp;@scripts = ["company.js"] &nbsp;&nbsp;end

This works, but again, when their is an error when the user submits wrong data, the javascripts/css files don't get loaded again. Its like the initialize action doesnt get executed again.

I hope you, or someone else can help me with those problems, becouse once they are out, I have a more solid application.

Thank you in advance

---

<div class="post-metadata">

**Author:** ![Jeff1](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jeff1/32/1170_2.png) [@Jeff1](https://discuss.rubyonrails.org/u/Jeff1)\
**Post date:** [August 5, 2008, 8:09pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/8 "2008-08-05T20:09:04Z")

</div>

> Hi Jeff

[snip]

Wow, I don't think I can respond to everything, but here are a couple of thoughts....

> The second problem lies in the create method.
> 
> @company.save && save\_user\_role\_associations
> 
> Here the @company gets save, even if their is an error in the save\_user\_role\_associations action. How can I handle this?

Wrap everything in a transaction:

transaction do &nbsp;&nbsp;@company.save! &nbsp;&nbsp;save\_user\_role\_assocations &nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;end end

If you raise an exception inside the block, AR will roll everything back for you.

> charm. But, the problem occurs when there is an error on the form submit. As you can see in my above example, I redirect to the new action. But then the related resources don't get loaded again, and that resides in an application crash. How can I make sure, the related resources are loaded again properly?

Don't redirect back to :new, you need to just \*render\* your form again. I know, sounds a bit weird, but otherwise you'll lose your instance variables, including all your validation errors. Just do:

render :action =\> :new

to redisplay your form.

Jeff

REST with Rails, Oct 4, 2008, Austin, TX: [http://www.purpleworkshops.com/workshops/rest-and-web-services](http://www.purpleworkshops.com/workshops/rest-and-web-services)

---

<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:** [August 6, 2008, 6:52am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/9 "2008-08-06T06:52:46Z")

</div>

Hi Jeff,

> If you raise an exception inside the block, AR will roll everything back for you.

The rollback did come to mind, but will that display the errors that I have set in my model?

> Don't redirect back to :new, you need to just \*render\* your form again. I know, sounds a bit weird, but otherwise you'll lose your instance variables, including all your validation errors. Just do:

> render :action =\> :new

> to redisplay your form.

This was my bad, I do rerender the form. But still I lose the instance variables that I have are related + it looks like the initialize action isn't invoked

Thank you for all your patience

---

<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:** [August 6, 2008, 3:17pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/10 "2008-08-06T15:17:12Z")

</div>

I can't believe that no one ever came across a similar problem.

It seems that nested resources still can cause some problems in Rails.

If anyone knows why my instance variables get lost or why the initialize action doesn't get invoked, please do tell me.

I'm eager to learn 🙂

---

<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:** [August 6, 2008, 7:47pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/11 "2008-08-06T19:47:17Z")

</div>

Michael Rigart wrote:

> I can't believe that no one ever came across a similar problem.
> 
> It seems that nested resources still can cause some problems in Rails.
> 
> If anyone knows why my instance variables get lost or why the initialize action doesn't get invoked, please do tell me.
> 
> I'm eager to learn 🙂

Ok, so what I have found out. When you invoke render :action =\> .... it doens't run the action. So all the related models don't get loaded again, I need to load them before the render :action statement 🙂

Invoking those actions can do look a bit nasty in the long run. Would it be a good idea to run them through a filter (like for example the before\_filter :only =\> )?

Now I havent got the time to see if the nested resources give their error messages. Going tot test this together with the rollbacks 🙂

---

<div class="post-metadata">

**Author:** ![Tonypm](https://avatars.discourse-cdn.com/v4/letter/t/a587f6/32.png) [@Tonypm](https://discuss.rubyonrails.org/u/Tonypm)\
**Post date:** [August 7, 2008, 7:17am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/12 "2008-08-07T07:17:18Z")

</div>

Also, I find using validates\_associated on the models concerned and then doing a valid? call on the top level object is quite a good way to get at the error messages and avoid trying to save objects only to find they have errors, although I still do use a transaction to ensure integrity.

Tonypm

---

<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:** [August 7, 2008, 7:20am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/13 "2008-08-07T07:20:44Z")

</div>

tonypm wrote:

> Also, I find using validates\_associated on the models concerned and then doing a valid? call on the top level object is quite a good way to get at the error messages and avoid trying to save objects only to find they have errors, although I still do use a transaction to ensure integrity.
> 
> Tonypm

Hi tonypm,

could you collaborate your statement a bit further? I don't understand it fully.

Thank you in advance

---

<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:** [August 7, 2008, 6:14pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/14 "2008-08-07T18:14:58Z")

</div>

Michael Rigart wrote:

> tonypm wrote:
> 
> > Also, I find using validates\_associated on the models concerned and then doing a valid? call on the top level object is quite a good way to get at the error messages and avoid trying to save objects only to find they have errors, although I still do use a transaction to ensure integrity.
> > 
> > Tonypm
> 
> Hi tonypm,
> 
> could you collaborate your statement a bit further? I don't understand it fully.
> 
> Thank you in advance

Ok, so lets say I'm saving data like this:

&nbsp;&nbsp;def create &nbsp;&nbsp;&nbsp;&nbsp;@company = Company.new(params[:company])

&nbsp;&nbsp;&nbsp;&nbsp;if @company.save && save\_user\_role\_associations &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flash[:message] = l("company\_create\_response") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect\_to(companies\_url) &nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add\_styles\_and\_scripts &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;relational\_objects &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render :action =\> "new" &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

private

&nbsp;&nbsp;def save\_user\_role\_associations &nbsp;&nbsp;&nbsp;&nbsp;saved\_ids =

&nbsp;&nbsp;&nbsp;&nbsp;params[:company\_user\_association].each do |key, item\_vals| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if item\_vals[:id].to\_i \> 0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association = CompanyRole.find(item\_vals[:id]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.update\_attributes(item\_vals) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association = CompanyRole.new(:company\_id =\> @company.id, :role\_id =\> item\_vals[:role\_id], :user\_id =\> item\_vals[:user\_id]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.save &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item\_vals.delete :id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saved\_ids \<\< association.id &nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;CompanyRole.find(:all, :conditions =\> ["company\_id = ? AND id NOT IN (?)",@company.id, saved\_ids]).each do |association| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.destroy &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

How do I implement the transaction in a clean way.

And how do I merge the CompanyRole errors when they occure? At this moment I display the company errors like this:

\<%= error\_messages\_for 'company', :header\_message =\> l("try\_again"), :message =\> l("message\_company") %\>

But I also want to display the CompanyRole errors in the same list as the company errors.

---

<div class="post-metadata">

**Author:** ![Tonypm](https://avatars.discourse-cdn.com/v4/letter/t/a587f6/32.png) [@Tonypm](https://discuss.rubyonrails.org/u/Tonypm)\
**Post date:** [August 8, 2008, 9:05am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/15 "2008-08-08T09:05:17Z")

</div>

Ok, what I am suggesting is to build the object and its associated objects before saving them. Then doing valid? is a good way to get at the error messages, and have all the objects constructed so you can render them. Create is a different case because you are trying to handle associations for an object that has not yet been created (ie. has no id). I will make a suggestion for Update

def update &nbsp;&nbsp;&nbsp;&nbsp;@company = Company.find(params[:id]) &nbsp;&nbsp;&nbsp;&nbsp;if @company.save\_company\_and\_roles(params[:company\_user\_association]) ........etc

In the Company model

validates\_associated :company\_role

def save\_company\_and\_company\_roles(roles) &nbsp;&nbsp;&nbsp;# first build the objects &nbsp;&nbsp;&nbsp;roles.each do |key, item\_vals| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if item\_vals[:id].to\_i \> 0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CompanyRole.find(item\_vals[:id]) = item\_vals &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;company\_roles.build(item\_vals) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;return false if !self.valid? # this should mostly avoid the transaction ever failing &nbsp;&nbsp;&nbsp;&nbsp;transaction do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.save &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;company\_roles.each { |r| r.save} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;company\_roles.find(:all, :conditions =\> [id NOT IN(?)", saved\_ids]).each do |association| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.destroy &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end end

By having this method in the model, using the company scoped finders tidies the code a bit. I have tweaked your code to reduce it a bit so I may have borked it, but you should be able to see what I am driving at. (Some of the self's are not actually needed)

In your view you can now use error\_messages\_for ['company', 'company\_role']. To improve the error messages, I actually go through the child objects and do add\_to\_base for the parent errors. This allows me to include the child id so that the error is more explicit.

For the create situation, I would start with a similar method to figure out what you want to do. Once you have that you will probably find you can do both together. Incidentally, if you do c=Company.new and then use c.company\_roles.build, then you can still do c.valid? to generate the errors.

Using the transaction, if there is any failure to save, then an exception will get raised which you may want to handle in the controller.

I dont see the Railscasts on complex forms mentioned in this thread, but I take it you have looked at those. Some great ideas in there.

> **[\#73 Complex Forms Part 1 - RailsCasts](http://railscasts.com/episodes/73-complex-forms-part-1)**
>
> Short Ruby on Rails screencasts containing tips, tricks and tutorials. Great for both novice and experienced web developers.

hope this makes some sort of sense Tonypm

---

<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:** [August 8, 2008, 9:10am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/16 "2008-08-08T09:10:21Z")

</div>

tonypm wrote:

> Ok, what I am suggesting is to build the object and its associated objects before saving them. Then doing valid? is a good way to get at the error messages, and have all the objects constructed so you can render them. Create is a different case because you are trying to handle associations for an object that has not yet been created (ie. has no id). I will make a suggestion for Update
> 
> def update &nbsp;&nbsp;&nbsp;&nbsp;@company = Company.find(params[:id]) &nbsp;&nbsp;&nbsp;&nbsp;if @company.save\_company\_and\_roles(params[:company\_user\_association]) ........etc
> 
> In the Company model
> 
> validates\_associated :company\_role
> 
> def save\_company\_and\_company\_roles(roles) &nbsp;&nbsp;&nbsp;# first build the objects &nbsp;&nbsp;&nbsp;roles.each do |key, item\_vals| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if item\_vals[:id].to\_i \> 0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CompanyRole.find(item\_vals[:id]) = item\_vals &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;company\_roles.build(item\_vals) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;return false if !self.valid? # this should mostly avoid the transaction ever failing &nbsp;&nbsp;&nbsp;&nbsp;transaction do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.save &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;company\_roles.each { |r| r.save} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;company\_roles.find(:all, :conditions =\> [id NOT IN(?)", saved\_ids]).each do |association| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.destroy &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end end
> 
> By having this method in the model, using the company scoped finders tidies the code a bit. I have tweaked your code to reduce it a bit so I may have borked it, but you should be able to see what I am driving at. (Some of the self's are not actually needed)
> 
> In your view you can now use error\_messages\_for ['company', 'company\_role']. To improve the error messages, I actually go through the child objects and do add\_to\_base for the parent errors. This allows me to include the child id so that the error is more explicit.
> 
> For the create situation, I would start with a similar method to figure out what you want to do. Once you have that you will probably find you can do both together. Incidentally, if you do c=Company.new and then use c.company\_roles.build, then you can still do c.valid? to generate the errors.
> 
> Using the transaction, if there is any failure to save, then an exception will get raised which you may want to handle in the controller.
> 
> I dont see the Railscasts on complex forms mentioned in this thread, but I take it you have looked at those. Some great ideas in there. [#73 Complex Forms Part 1 - RailsCasts](http://railscasts.com/episodes/73-complex-forms-part-1)
> 
> hope this makes some sort of sense Tonypm

Thi Tonypm,

thanks for you explenation. I will look in to it this weekend, since I'm working on another part of the project today and I need to finish the rewrite by the end of next week.

You example does make sense, and I also found the railcast threads on complex forms this morning, so I'm definataly going to take a look at it.

When I come up with a working solution, I'll post my actions here, so it might help other people in the future if they run into a similar problem.

---

<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:** [August 8, 2008, 1:52pm UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/17 "2008-08-08T13:52:26Z")

</div>

Hi Tonypm

I couldn't resist and start working on it now. And I think I'm almost there. For good testing perposes I've implemented the algoritm in a my invoices, witch has many invoice\_items. The filosophie is the same with companies and roles.

So in my invoice model, I've added:

..... has\_many :invoice\_items validates\_associated :invoice\_items

&nbsp;&nbsp;def save\_outgoing\_invoice\_and\_items(items) &nbsp;&nbsp;&nbsp;&nbsp;saved\_ids =

&nbsp;&nbsp;&nbsp;&nbsp;return false unless self.valid?

&nbsp;&nbsp;&nbsp;&nbsp;transaction do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.save

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;items.each do |key, item\_vals| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if item\_vals[:id].to\_i \> 0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item = OutgoingInvoiceItem.find(item\_vals[:id]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.attributes = item\_vals &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item = OutgoingInvoiceItem.new(item\_vals) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;item.save

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saved\_ids \<\< item.id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outgoing\_invoice\_items.find(:all, :conditions =\> ["id NOT IN (?)", saved\_ids]).each do |association| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;association.destroy &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end .....

Then in the invoice controller, I call the model action to save the invoice and the items:

&nbsp;&nbsp;&nbsp;if @outgoing\_invoice.save\_outgoing\_invoice\_and\_items(params[:outgoing\_invoice\_item])

Then in my view I have \<%= error\_messages\_for ['invoice', 'invoice\_items'], :header\_message =\> l("try\_again"), :message =\> l("message\_invoice") %\>

To display the error messages.

The thing now is, that when I make a mistake in the invoice\_items, the invoice gets saved without any invoice\_items, and I don't get any error messages saying that something went wrong. So the transaction doesn't rollback the parent entry, only the child entries + the fact that I miss some error reporting.

I can feel it will be something stupid that I overlooked.

PS: The way the model action is now written, it can be used for both create and update

---

<div class="post-metadata">

**Author:** ![Tonypm](https://avatars.discourse-cdn.com/v4/letter/t/a587f6/32.png) [@Tonypm](https://discuss.rubyonrails.org/u/Tonypm)\
**Post date:** [August 10, 2008, 11:42am UTC](https://discuss.rubyonrails.org/t/rest-nested-resources/32452/18 "2008-08-10T11:42:00Z")

</div>

I think the problem is that you are not building the object before you do the valid? test. Which means validation will pass, but then in the transaction, validation will fail so that the invoice\_item will not get saved, but the transaction will not fail because a validation error is soft. It doesn't raise an exception.

If you want to break the transaction you would need to do a raise if the save is false. But then you would need to handle the exception in the controller - and of course subsequent items would not get saved or loaded into the objects so you would not get their values re- displayed.

That is why in my example, I build the objects first, then do the valid? check and then open the transaction and do the saves.

So the valid? is there to trap normal user errors, and the transaction is there to trap unexpected system errors. Which means that if for some reason a save fails unexpectedly, the database is not left in an possible inconsistent state.

hth Tonypm
