I have a new @offer that needs to generate a document if saved. But that''s all or nothing: transaction do @offer.save! generate_document end # handle exceptions if needed If save! fails everything is fine, but if generate_document raises an exception @offer is left as a model with timestamps, id, which is not a new_record? anymore (though the database was rolled back). I''ve played a bit cloning, and with the object transaction plugin, but I am not satisfied with the solutions. Problem is we need to rollback the object except its errors, so to speak. Do you have any best practices for this? -- fxn --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
I''m not 100% sure on this, but I think what you''re looking for is ActiveRecord::Observer. See this example that is used to send an email after saving comments to what I assume is a blogging application: class CommentObserver < ActiveRecord::Observer def after_save(comment) Notifications.deliver_comment("admin-zIEGH9a+O8I@public.gmane.org", "New comment was posted", comment) end end On Apr 30, 1:21 pm, Xavier Noria <f...-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote:> I have a new @offer that needs to generate a document if saved. But > that''s all or nothing: > > transaction do > @offer.save! > generate_document > end > # handle exceptions if needed > > If save! fails everything is fine, but if generate_document raises an > exception @offer is left as a model with timestamps, id, which is not > a new_record? anymore (though the database was rolled back). > > I''ve played a bit cloning, and with the object transaction plugin, but > I am not satisfied with the solutions. Problem is we need to rollback > the object except its errors, so to speak. > > Do you have any best practices for this? > > -- fxn--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
On May 1, 2008, at 2:00 , Robert Walker wrote:> > I''m not 100% sure on this, but I think what you''re looking for is > ActiveRecord::Observer. > > See this example that is used to send an email after saving comments > to what I assume is a blogging application: > > class CommentObserver < ActiveRecord::Observer > def after_save(comment) > Notifications.deliver_comment("admin-zIEGH9a+O8I@public.gmane.org", "New comment was > posted", comment) > end > endThank you, problem is that the document is not always generated. By now the best I''ve got is rollback_active_record_state! do transaction do save! generate_document end end # handle exceptions self preserves the @new_record flag and id housekeeping. It still has created_at even if it was not actually created, but is the better solution I''ve seen so far. -- fxn --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
I guess I''m not seeing the problem. What do you mean by?> Thank you, problem is that the document is not always generated.Does this mean that if the document fails to generate then the offer should not save to the database and remain as a new (unsaved) object? I am assuming that you only want to create the document when creating offers, not updating existing offers. If that''s the case, then the observer should implement after_create instead of after_save. If anything goes wrong during create_document and it raises an exception then ActiveRecord will not insert the offer, and you should still have a new Offer object. Then you can present errors back to the user, or whatever error handling you need to do. I suppose I must be missing something obvious here, but I can''t think of what that might be. On Apr 30, 8:35 pm, Xavier Noria <f...-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote:> On May 1, 2008, at 2:00 , Robert Walker wrote: > > > > > I''m not 100% sure on this, but I think what you''re looking for is > > ActiveRecord::Observer. > > > See this example that is used to send an email after saving comments > > to what I assume is a blogging application: > > > class CommentObserver < ActiveRecord::Observer > > def after_save(comment) > > Notifications.deliver_comment("ad...-zIEGH9a+O8I@public.gmane.org", "New comment was > > posted", comment) > > end > > end > > Thank you, problem is that the document is not always generated. > > By now the best I''ve got is > > rollback_active_record_state! do > transaction do > save! > generate_document > end > end > # handle exceptions > > self preserves the @new_record flag and id housekeeping. It still has > created_at even if it was not actually created, but is the better > solution I''ve seen so far. > > -- fxn--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
Never mind. I think I see the problem now. You need the document to be created when and only when the offer creates successfully, and you also need the offer to roll back if the document creation fails. Is your create_document method inside of the Offer model class or is it in a different class? The observer allows you to move this rather unrelated code outside of the model object (since creating the document is not a direct responsibility of the Offer model class). Normally doing before_create inside the model class and returning false in that method if something goes wrong will suspend the callback chain, and will leave your table in an unaltered state. However, returning false from the before_create implementation inside the observer does not appear to suspend the callback chain. So this must be why you are using transactions to work around this problem. Out of curiosity would create_document be creating database records? If that''s the case then transactions would likely be necessary anyway. On Apr 30, 9:05 pm, Robert Walker <r0b3rt4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I guess I''m not seeing the problem. > > What do you mean by? > > > Thank you, problem is that the document is not always generated. > > Does this mean that if the document fails to generate then the offer > should not save to the database and remain as a new (unsaved) object? > > I am assuming that you only want to create the document when creating > offers, not updating existing offers. If that''s the case, then the > observer should implement after_create instead of after_save. If > anything goes wrong during create_document and it raises an exception > then ActiveRecord will not insert the offer, and you should still have > a new Offer object. Then you can present errors back to the user, or > whatever error handling you need to do. > > I suppose I must be missing something obvious here, but I can''t think > of what that might be. > > On Apr 30, 8:35 pm, Xavier Noria <f...-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote: > > > On May 1, 2008, at 2:00 , Robert Walker wrote: > > > > I''m not 100% sure on this, but I think what you''re looking for is > > > ActiveRecord::Observer. > > > > See this example that is used to send an email after saving comments > > > to what I assume is a blogging application: > > > > class CommentObserver < ActiveRecord::Observer > > > def after_save(comment) > > > Notifications.deliver_comment("ad...-zIEGH9a+O8I@public.gmane.org", "New comment was > > > posted", comment) > > > end > > > end > > > Thank you, problem is that the document is not always generated. > > > By now the best I''ve got is > > > rollback_active_record_state! do > > transaction do > > save! > > generate_document > > end > > end > > # handle exceptions > > > self preserves the @new_record flag and id housekeeping. It still has > > created_at even if it was not actually created, but is the better > > solution I''ve seen so far. > > > -- fxn--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
On May 1, 2008, at 3:41 , Robert Walker wrote:> Never mind. I think I see the problem now. You need the document to be > created when and only when the offer creates successfully, and you > also need the offer to roll back if the document creation fails.That''s right.> Is your create_document method inside of the Offer model class or is > it in a different class? The observer allows you to move this rather > unrelated code outside of the model object (since creating the > document is not a direct responsibility of the Offer model class).Well in this case an offer knows how to generate its own document. Note than an observer as far as this problem is concerned is not much different than a regular AR callback. I mean, the techique that does not work is after_*, no matter whether it is in the model or in an observer. after_* does not work for what I need because the offer is not aware of whether it needs to save a document or not, so I can''t put the conditional in the callback. I think I can revise that, but even if it knew it you can''t rollback the INSERT in an after_create, you can abort in before_*s. Well you could raise an exception in after_*s, but that''s unexpected behaviour because you do not expect @offer.save to raise an exception like that. So what I do with rollback_active_record_state! is basically what AR does, plus catching exceptions from document generation. With that code I can implement the transaction I need, have @offer (almost) restored, and return a controlled boolean as usual. if @offer.save_and_generate_document # ... end I think leaving timestamps with the new values is a bug. I mean, a new_record? shouldn''t have a timestamp in created_at, I can live with that though I''ll try to determine if that''s a bug and fill a ticket if that''s the case. Thank you for helping Robert. -- fxn --~--~---------~--~----~------------~-------~--~----~ 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 Thu, May 1, 2008 at 11:58 AM, Xavier Noria <fxn-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote:> I think leaving timestamps with the new values is a bug. I mean, a > new_record? shouldn''t have a timestamp in created_at, I can live with that > though I''ll try to determine if that''s a bug and fill a ticket if that''s the > case.Here it is: http://rails.lighthouseapp.com/projects/8994/tickets/93-restore-timestamps-in-model-rollback#ticket-93-1 --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---