I''ve recently upgraded to rails 2.0. Previously all my controllers were traditional :controller/:action/:id based. I''ve now decided to go down the REST route for new controllers etc. So I''ve got a controller to do the create method for two models: Licensee and licensee_address together in one form The form tags looks like: <% form_for([:agent, @licensee]) do |f| %> ..... <% fields_for(@licensee_address) do |fl| %> and the controller code for the posted data looks like: # POST /agent/licensees # POST /agent/licensees.xml def create @licensee = Licensee.new(params[:licensee]) @licensee.active = true @licensee.agent = @auth_agent @licensee_address = LicenseeAddress.new(params[:licensee_address]) @licensee_address.licensee = @licensee respond_to do |format| begin Licensee.transaction do @licensee.save! @licensee_address.save! # must assign a unique licensee ref @licensee.licensee_ref = "%s%04d" % [@licensee.name[0,3],@licensee.id] @licensee.active = true @licensee.save! end flash[:notice] = ''Licensee was successfully created.'' format.html { redirect_to(agent_licensees_url) } format.xml { render :xml => @licensee, :status => :created, :location => @licensee } rescue ActiveRecord::RecordInvalid => e #make sure we catch any validation errors on the address @licensee_address.valid? format.html { render :action => "new" } format.xml { render :xml => @licensee.errors, :status => :unprocessable_entity } end end end Which all works splendidly if there are no validation errors. However, if the are validation errors in the licensee_address, I have problems. The licensee record was (temporarily) saved OK to the database so gets a valid id and is no longer a "new" record. The saving of the licensee_address fails. The transaction is rolled back so the database is OK. The problem comes with re-rendering the form to show the errors. The licensee now looks like a valid record from the database and so the form tag renders this as if it should post to an update method (i.e with a PUT method and a valid id. This is clearly wrong. If I now correct the error on the form and resubmit, the update method gets called and the whole thing blows up! Is there any way to tell an activerecord object that it was not really saved to the database as it was rolled back? Is there any nice way to do this kind of thing? Cheers, Gary. --~--~---------~--~----~------------~-------~--~----~ 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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
stephen.celis-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2008-Jan-20 14:42 UTC
Re: REST Validation dilemma
You could check the validity of both items before saving. if @licensee.valid? and @licensee_address.valid? ... On Jan 20, 8:14 am, Gary Doades <g...-UVRRe/+0hzLQXOPxS62xeg@public.gmane.org> wrote:> I''ve recently upgraded to rails 2.0. Previously all my controllers were > traditional :controller/:action/:id based. I''ve now decided to go down > the REST route for new controllers etc. > > So I''ve got a controller to do the create method for two models: > Licensee and licensee_address together in one form > > The form tags looks like: > > <% form_for([:agent, @licensee]) do |f| %> > ..... > <% fields_for(@licensee_address) do |fl| %> > > and the controller code for the posted data looks like: > > # POST /agent/licensees > # POST /agent/licensees.xml > def create > @licensee = Licensee.new(params[:licensee]) > -JvV4GCjhi6dIi0J7XieuPw@public.gmane.org = true > -JvV4GCjhi6eWnvMS3xHScg@public.gmane.org = @auth_agent > @licensee_address = LicenseeAddress.new(params[:licensee_address]) > @licensee_address.licensee = @licensee > > respond_to do |format| > begin > Licensee.transaction do > -JvV4GCjhi6ezOeKtxYPyNA@public.gmane.org! > @licensee_address.save! > # must assign a unique licensee ref > -JvV4GCjhi6ex/+Ph+b8bcbNAH6kLmebB@public.gmane.org_ref = "%s%04d" % > [@licensee.name[0,3],@licensee.id] > -JvV4GCjhi6dIi0J7XieuPw@public.gmane.org = true > -JvV4GCjhi6ezOeKtxYPyNA@public.gmane.org! > end > flash[:notice] = ''Licensee was successfully created.'' > format.html { redirect_to(agent_licensees_url) } > format.xml { render :xml => @licensee, :status => :created, > :location => @licensee } > rescue ActiveRecord::RecordInvalid => e > #make sure we catch any validation errors on the address > @licensee_address.valid? > format.html { render :action => "new" } > format.xml { render :xml => @licensee.errors, :status => > :unprocessable_entity } > end > end > end > > Which all works splendidly if there are no validation errors. However, > if the are validation errors in the licensee_address, I have problems. > > The licensee record was (temporarily) saved OK to the database so gets a > valid id and is no longer a "new" record. The saving of the > licensee_address fails. The transaction is rolled back so the database > is OK. > > The problem comes with re-rendering the form to show the errors. The > licensee now looks like a valid record from the database and so the form > tag renders this as if it should post to an update method (i.e with a > PUT method and a valid id. This is clearly wrong. If I now correct the > error on the form and resubmit, the update method gets called and the > whole thing blows up! > > Is there any way to tell an activerecord object that it was not really > saved to the database as it was rolled back? Is there any nice way to do > this kind of thing? > > Cheers, > Gary.--~--~---------~--~----~------------~-------~--~----~ 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-/JYPxA39Uh5TLH3MbocFFw@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 the suggestion. Yes, I could, but my example was over simplified to save space. My point is that I could have any number of operations/models in the transaction and any one of them could cause an exception. I was just wondering if there was a more general way of doing this is a safe fashion whilst still adhering to "standard" principles. Cheers, Gary. stephen.celis-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:> You could check the validity of both items before saving. > > if @licensee.valid? and @licensee_address.valid? > ... > > On Jan 20, 8:14 am, Gary Doades <g...-UVRRe/+0hzLQXOPxS62xeg@public.gmane.org> wrote: >> I''ve recently upgraded to rails 2.0. Previously all my controllers were >> traditional :controller/:action/:id based. I''ve now decided to go down >> the REST route for new controllers etc. >> >> So I''ve got a controller to do the create method for two models: >> Licensee and licensee_address together in one form >> >> The form tags looks like: >> >> <% form_for([:agent, @licensee]) do |f| %> >> ..... >> <% fields_for(@licensee_address) do |fl| %> >> >> and the controller code for the posted data looks like: >> >> # POST /agent/licensees >> # POST /agent/licensees.xml >> def create >> @licensee = Licensee.new(params[:licensee]) >> @licensee.active = true >> @licensee.agent = @auth_agent >> @licensee_address = LicenseeAddress.new(params[:licensee_address]) >> @licensee_address.licensee = @licensee >> >> respond_to do |format| >> begin >> Licensee.transaction do >> @licensee.save! >> @licensee_address.save! >> # must assign a unique licensee ref >> @licensee.licensee_ref = "%s%04d" % >> [@licensee.name[0,3],@licensee.id] >> @licensee.active = true >> @licensee.save! >> end >> flash[:notice] = ''Licensee was successfully created.'' >> format.html { redirect_to(agent_licensees_url) } >> format.xml { render :xml => @licensee, :status => :created, >> :location => @licensee } >> rescue ActiveRecord::RecordInvalid => e >> #make sure we catch any validation errors on the address >> @licensee_address.valid? >> format.html { render :action => "new" } >> format.xml { render :xml => @licensee.errors, :status => >> :unprocessable_entity } >> end >> end >> end >> >> Which all works splendidly if there are no validation errors. However, >> if the are validation errors in the licensee_address, I have problems. >> >> The licensee record was (temporarily) saved OK to the database so gets a >> valid id and is no longer a "new" record. The saving of the >> licensee_address fails. The transaction is rolled back so the database >> is OK. >> >> The problem comes with re-rendering the form to show the errors. The >> licensee now looks like a valid record from the database and so the form >> tag renders this as if it should post to an update method (i.e with a >> PUT method and a valid id. This is clearly wrong. If I now correct the >> error on the form and resubmit, the update method gets called and the >> whole thing blows up! >> >> Is there any way to tell an activerecord object that it was not really >> saved to the database as it was rolled back? Is there any nice way to do >> this kind of thing? >> >> Cheers, >> Gary. > >--~--~---------~--~----~------------~-------~--~----~ 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-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---