I have a pair of models: class Document < ActiveRecord::Base has_many :revisions # attributes: Title, Number, etc... end Class Revision < ActiveRecord::Base belongs_to :Document # attributes: document_id, revision, release_status, etc.. end I have a controller & view for the Revision model (note, this is the model that belongs to the Document model). the "edit" view looks something like this: <% form_for(@revision) do |f| %> <% fields_for(@revision.number) do |r| %> <%= r.text_field :title %> <%= r.text_field :number %> ... When my "update" method gets called, how can I update the corresponding "revision.number" record simultaneously with updating my "revision" record? I know I can do something like this: success = @revision.number.update_attributes(params[:number]) success &= @revision.update_attributes(params[:revision]) but, what happens if the second call to "update_attributes" fails? I will have updated the Number model, but not the Revision model. Is there an idiomatic way to handle this? I suppose I could rethink my application, and write a documents controller & view and update the revision as part of updating the document. But I would like to know how to update the parent of a belongs_to association regardless. Thanks for your advice and enlightenment. --wpd --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Document.transaction do # update the revision # update the document end If one fails, you rollback the transaction and you''re done; no half-modified record pairs. Brent Patrick Doyle wrote:> I have a pair of models: > > class Document < ActiveRecord::Base > has_many :revisions > > # attributes: Title, Number, etc... > end > > Class Revision < ActiveRecord::Base > belongs_to :Document > > # attributes: document_id, revision, release_status, etc.. > end > > I have a controller & view for the Revision model (note, this is the > model that belongs to the Document model). > the "edit" view looks something like this: > <% form_for(@revision) do |f| %> > <% fields_for(@revision.number) do |r| %> > <%= r.text_field :title %> > <%= r.text_field :number %> > ... > > When my "update" method gets called, how can I update the > corresponding "revision.number" record simultaneously with updating my > "revision" record? > > I know I can do something like this: > success = @revision.number.update_attributes(params[:number]) > success &= @revision.update_attributes(params[:revision]) > > but, what happens if the second call to "update_attributes" fails? I > will have updated the Number model, but not the Revision model. > > Is there an idiomatic way to handle this? > > I suppose I could rethink my application, and write a documents > controller & view and update the revision as part of updating the > document. But I would like to know how to update the parent of a > belongs_to association regardless. > > Thanks for your advice and enlightenment. > > --wpd-- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Let''s say that we wanted to do the same thing, only as part of a plugin. For instance, say we are creating a plugin called acts_as_cached that causes a set of fields in a shadow model to be updated whenever the target model is created/updated. The natural implementation is to locate or create the shadow record and update the fields using the appropriate callback. The problem with using transactions in this case is that there don''t seem to be any good ways to specify or finalize the transaction with callbacks. Without transactions, there is no guarantee that things will get saved or recovered on errors. With transactions, there is no way to start and finish the transaction in the same callback but still save the both records at the right spot in the callback chain. Note that observers won''t work -- they aren''t transactional. The only thing I can think of is to alias wrap the target class state- changing methods (create, update, destroy) and put the transaction code in there, in turn calling the previous CUD operations inside a transaction. Any ideas? -ns Brent Miller wrote:> Document.transaction do > # update the revision > # update the document > end > > If one fails, you rollback the transaction and you''re done; no > half-modified record pairs. > > Brent > > Patrick Doyle wrote: > > I have a pair of models: > > > > class Document < ActiveRecord::Base > > has_many :revisions > > > > # attributes: Title, Number, etc... > > end > > > > Class Revision < ActiveRecord::Base > > belongs_to :Document > > > > # attributes: document_id, revision, release_status, etc.. > > end > > > > I have a controller & view for the Revision model (note, this is the > > model that belongs to the Document model). > > the "edit" view looks something like this: > > <% form_for(@revision) do |f| %> > > <% fields_for(@revision.number) do |r| %> > > <%= r.text_field :title %> > > <%= r.text_field :number %> > > ... > > > > When my "update" method gets called, how can I update the > > corresponding "revision.number" record simultaneously with updating my > > "revision" record? > > > > I know I can do something like this: > > success = @revision.number.update_attributes(params[:number]) > > success &= @revision.update_attributes(params[:revision]) > > > > but, what happens if the second call to "update_attributes" fails? I > > will have updated the Number model, but not the Revision model. > > > > Is there an idiomatic way to handle this? > > > > I suppose I could rethink my application, and write a documents > > controller & view and update the revision as part of updating the > > document. But I would like to know how to update the parent of a > > belongs_to association regardless. > > > > Thanks for your advice and enlightenment. > > > > --wpd > > -- > Posted via http://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
On Sun, Jun 22, 2008 at 1:49 AM, Brent Miller <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> > Document.transaction do > # update the revision > # update the document > end > > If one fails, you rollback the transaction and you''re done; no > half-modified record pairs.Thanks... I thought about using a transaction, but couldn''t find any description of it in my "The Rails Way" book -- at least it''s not in the index anywhere, and I couldn''t find it in the ActiveRecord chapters I skimmed. I was a little concerned that a transaction seemed to be specific to a single model (the "Document.transaction" part scared me.) But I now see in the API that the records need not all be instances of that class. Looking at the API, all of the examples use the #save! method. Should I be concerned that I am using the #update_attributes method? Or should I presume that it does the right thing. Hmmm... looking more carefully, I see an #update_attributes! method that will throw an exception if the update fails (actually, if the #save! fails). I''m not sure what you mean by "you rollback the transaction". It seems to me that the rollback would occur automatically if something bad, say an exception, occurred. Do I have the gist of this right? Or is there something else I need to do to roll it back? Finally, I have this niggling suspicion that I read somewhere that the use of transactions was deprecated, but I could be confusing that with something else. Again, thanks for pointing me in a promising direction. --wpd --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
You''re right that you should use the update_attributes! bang method, because it will fail with an exception. Throwing an exception inside a transaction block causes the transaction to rollback. That''s how you cause a rollback to happen. You should still rescue the exception and handle it somehow, at the very least by presenting an error message to the user. Transactions are still very much supported, and actually we may be getting nested transactions soon, which would be a boon for testing: http://rails.lighthouseapp.com/projects/8994/tickets/383-activerecord-should-use-savepoints-for-nested-transactions Good luck! Patrick Doyle wrote:> On Sun, Jun 22, 2008 at 1:49 AM, Brent Miller > <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote: >> >> Document.transaction do >> # update the revision >> # update the document >> end >> >> If one fails, you rollback the transaction and you''re done; no >> half-modified record pairs. > Thanks... > I thought about using a transaction, but couldn''t find any description > of it in my "The Rails Way" book -- at least it''s not in the index > anywhere, and I couldn''t find it in the ActiveRecord chapters I > skimmed. > > I was a little concerned that a transaction seemed to be specific to a > single model (the "Document.transaction" part scared me.) But I now > see in the API that the records need not all be instances of that > class. > > Looking at the API, all of the examples use the #save! method. Should > I be concerned that I am using the #update_attributes method? Or > should I presume that it does the right thing. Hmmm... looking more > carefully, I see an #update_attributes! method that will throw an > exception if the update fails (actually, if the #save! fails). I''m > not sure what you mean by "you rollback the transaction". It seems to > me that the rollback would occur automatically if something bad, say > an exception, occurred. Do I have the gist of this right? Or is > there something else I need to do to roll it back? > > Finally, I have this niggling suspicion that I read somewhere that the > use of transactions was deprecated, but I could be confusing that with > something else. > > Again, thanks for pointing me in a promising direction. > > --wpd-- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Fabulous! Thank you very much. --wpd --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Jun-23 09:35 UTC
Re: How to update parent of a belongs_to association
On 23 Jun 2008, at 00:33, Patrick Doyle wrote:> > On Sun, Jun 22, 2008 at 1:49 AM, Brent Miller > <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote: >> >> Document.transaction do >> # update the revision >> # update the document >> end >> >> If one fails, you rollback the transaction and you''re done; no >> half-modified record pairs. > Thanks... > I thought about using a transaction, but couldn''t find any description > of it in my "The Rails Way" book -- at least it''s not in the index > anywhere, and I couldn''t find it in the ActiveRecord chapters I > skimmed. > > I was a little concerned that a transaction seemed to be specific to a > single model (the "Document.transaction" part scared me.) But I now > see in the API that the records need not all be instances of that > class. >Document.transaction is just shorthand for Document.connection.transaction: the only time the class upon which you call transaction is relevant is when your model classes are spread across multiple databases and you need to be sure that you''re creating transactions in the right one. If you don''t like looking like you''re favouring one model you could always use ActiveRecord::Base.transaction> > Finally, I have this niggling suspicion that I read somewhere that the > use of transactions was deprecated, but I could be confusing that with > something else.What was deprecated (or even removed, can''t remember) was object transactions, ie a rollback triggering the rollback of a ruby object (instance variables etc...) Fred --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
On Mon, Jun 23, 2008 at 5:35 AM, Frederick Cheung <frederick.cheung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Document.transaction is just shorthand for > Document.connection.transaction: the only time the class upon which > you call transaction is relevant is when your model classes are spread > across multiple databases and you need to be sure that you''re creating > transactions in the right one. If you don''t like looking like you''re > favouring one model you could always use ActiveRecord::Base.transactionWhich is more common in the community? MyModel.transaction or ActiveRecord::Base.transaction One of the challenges of learning to speak any foreign language is learning the idioms, because the literal translation seems strange in one''s native tongue. Hence the use of "MyModel.transaction" feels strange to me, but if that is the idiom that is typically used (and I suspect it is), then I can start using it as well and gain slightly more fluency in this "RoR" language and the culture I am (very slowly) joining.>> >> Finally, I have this niggling suspicion that I read somewhere that the >> use of transactions was deprecated, but I could be confusing that with >> something else. > > What was deprecated (or even removed, can''t remember) was object > transactions, ie a rollback triggering the rollback of a ruby object > (instance variables etc...)Ahhh.... now that I read that, I do seem to recall seeing the word "object" in front of the word "transaction". OK, I''ll use transactions in the full confidence that they are the right way to solve this sort of problem. Thanks to both of you for the help and insight. --wpd --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---