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
has_many :clients
....
class Client < ActiveRecord::Base
belongs_to :person
validates_presence_of :person_id
....
def create
@client = Client.new(params[:client])
begin #check if the person already exists
@person=Person.find(params[:person][:id])
rescue #otherwise create new person
@person=Person.new(params[:person])
end
@client.person=@person
begin
Client.transaction do
@person.save!
@client.person=@person
@client.save!
flash[:notice] = ''Client was successfully created.''
redirect_to :action => ''edit'', :id => @client.id
end
rescue
render :action => ''new''
end
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
--
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.
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. On Dec 22, 8:30 pm, giorgio <george.pever...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> 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 > has_many :clients > .... > > class Client < ActiveRecord::Base > belongs_to :person > validates_presence_of :person_id > > .... > > def create > @client = Client.new(params[:client]) > begin #check if the person already exists > @person=Person.find(params[:person][:id]) > rescue #otherwise create new person > @person=Person.new(params[:person]) > end > @client.person=@person > begin > Client.transaction do > @person.save! > @client.person=@person > @client.save! > flash[:notice] = ''Client was successfully created.'' > redirect_to :action => ''edit'', :id => @client.id > end > rescue > render :action => ''new'' > end > 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-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
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:
def create
begin #try to find existing person
@person=Person.find(params[:person][:id])
rescue #they dont exist so create new
@person=Person.new(params[:person])
end
person_id=@person.id
@client=Client.new(params[:client])
begin
Person.transaction do
@person.save!
@client.person=@person
@client.save!
flash[:notice] = ''Client was successfully created.''
redirect_to :action => ''edit'', :id => @client.id
end
rescue
#reset client and person to param values
@person.id=person_id
render :action => ''new''
end
end
Cheers
George
--
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.
> 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. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.