# Saving records from multiple tables

**URL:** <https://discuss.rubyonrails.org/t/saving-records-from-multiple-tables/56406>\
**Category:** rubyonrails-talk\
**Created:** [December 23, 2010, 1:30am UTC](https://discuss.rubyonrails.org/t/saving-records-from-multiple-tables/56406 "2010-12-23T01:30:20Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![giorgio](https://avatars.discourse-cdn.com/v4/letter/g/cab0a1/32.png) [@giorgio](https://discuss.rubyonrails.org/u/giorgio)\
**Post date:** [December 23, 2010, 1:30am UTC](https://discuss.rubyonrails.org/t/saving-records-from-multiple-tables/56406/1 "2010-12-23T01:30:20Z")

</div>

I hav page where I am saving a "client" record and a "person" record. Sometimes the "person" is an existing record and sometimes it is a new record. The "client" is always new. Here is some code:

class Person \< ActiveRecord::Base &nbsp;&nbsp;has\_many :clients ....

class Client \< ActiveRecord::Base &nbsp;&nbsp;belongs\_to :person &nbsp;&nbsp;validates\_presence\_of :person\_id

....

&nbsp;&nbsp;def create &nbsp;&nbsp;&nbsp;&nbsp;@client = Client.new(params[:client]) &nbsp;&nbsp;&nbsp;&nbsp;begin #check if the person already exists &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person=Person.find(params[:person][:id]) &nbsp;&nbsp;&nbsp;&nbsp;rescue #otherwise create new person &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person=Person.new(params[:person]) &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;@client.person=@person &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Client.transaction do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person.save! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@client.person=@person &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@client.save! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = 'Client was successfully created.' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :action =\> 'edit', :id =\> @client.id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;rescue &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render :action =\> 'new' &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

Im not really sure what the best way and order to do the saves is. If I try to save client first then it wont have a person\_id yet and will fail validation. If I save the person first and then the client fails validation for some other reason the code sort of works in that it rolls back but the @person record has an id set even though the save failed. It also appears to return false for @person.new\_record?

Is there a tidier way to do this? I have tried @client.person.save and various other combinations but it is not really clear what actually gets saved.

Any comments appreciated.

George

---

<div class="post-metadata">

**Author:** ![pepe1](https://avatars.discourse-cdn.com/v4/letter/p/dec6dc/32.png) [@pepe1](https://discuss.rubyonrails.org/u/pepe1)\
**Post date:** [December 23, 2010, 2:39pm UTC](https://discuss.rubyonrails.org/t/saving-records-from-multiple-tables/56406/2 "2010-12-23T14:39:20Z")

</div>

I see 2 things that might help you. On one hand you could use accepts\_nested\_attributes\_for in your person model and fields\_for in your view, then you would only need to save the person and that would take care of the client as well but based on what I see in your code that might not be feasible. On the other hand you could wrap the code for your save commands in a transaction and if there is any type of error during any of the saves Rails will roll back the transaction and you're golden.

---

<div class="post-metadata">

**Author:** ![giorgio](https://avatars.discourse-cdn.com/v4/letter/g/cab0a1/32.png) [@giorgio](https://discuss.rubyonrails.org/u/giorgio)\
**Post date:** [December 23, 2010, 8:46pm UTC](https://discuss.rubyonrails.org/t/saving-records-from-multiple-tables/56406/3 "2010-12-23T20:46:27Z")

</div>

Thanks for reply pepe. You say to use a transaction... I already am using a transaction!

The issue is that if the person save succeeds and the client save fails then the transaction is rolled back fine. However the person record now has a person.id and subsequent code assumes that the record is saved and tries to refind the record which of course does not exist.

I have got around this by saving the original value of the person.id and then resetting it in the rescue clause but it is a bit messy.

One other issue is that the only validation errors that get set are the errors from the first record (person) that is saved so the user may fix these up only to find new validation errors from the second record...

I'm sure there must be a tidy way!

My latest version which works but is not pretty is:

&nbsp;&nbsp;def create &nbsp;&nbsp;&nbsp;&nbsp;begin #try to find existing person &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person=Person.find(params[:person][:id]) &nbsp;&nbsp;&nbsp;&nbsp;rescue #they dont exist so create new &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person=Person.new(params[:person]) &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;person\_id=@person.id

&nbsp;&nbsp;&nbsp;&nbsp;@client=Client.new(params[:client]) &nbsp;&nbsp;&nbsp;&nbsp;begin &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person.transaction do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person.save! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@client.person=@person &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@client.save! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = 'Client was successfully created.' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :action =\> 'edit', :id =\> @client.id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;rescue &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#reset client and person to param values &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@person.id=person\_id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;render :action =\> 'new' &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;end

Cheers George

---

<div class="post-metadata">

**Author:** ![pepe1](https://avatars.discourse-cdn.com/v4/letter/p/dec6dc/32.png) [@pepe1](https://discuss.rubyonrails.org/u/pepe1)\
**Post date:** [December 23, 2010, 9:26pm UTC](https://discuss.rubyonrails.org/t/saving-records-from-multiple-tables/56406/4 "2010-12-23T21:26:19Z")

</div>

> You say to use a transaction... I already am using a transaction!

Sorry about that. I obviously didn't read carefully your post.

> The issue is that if the person save succeeds and the client save fails then the transaction is rolled back fine. However the person record now has a person.id and subsequent code assumes that the record is saved and tries to refind the record which of course does not exist.
> 
> I have got around this by saving the original value of the person.id and then resetting it in the rescue clause but it is a bit messy.
> 
> One other issue is that the only validation errors that get set are the errors from the first record (person) that is saved so the user may fix these up only to find new validation errors from the second record...

I have not tried before what you are trying to do but I will as soon as I have some time to spare. I don't understand why Rails would not clear the ID value of the record and reset the record in order for new\_record? to return true.

> I'm sure there must be a tidy way!

If you use acceptes\_nested\_attributes\_for and field\_for the validations will work just like you want them to work, however you will need to change your form to be based on your person model, which based on what you have explained would be pretty much impossible since the person is selected in the form and you don't have a person object to base the form on.
