Peter Marklund

Peter Marklund's Home


Rails and Transactional Saves

Correction: ActiveRecord::Base#save does use transactions in Rails by default, see Jarkkos comment.

In Rails, models are not saved within a database transaction by default. This means that if you are updating some other record in a callback like after_save then the record will still be saved even if an exception is raised in the callback. If you care a lot about data integrity this is not satisfactory. One way to remedy the problem might be to simply override the save and save! methods in your model like this:

  def save
    Post.transaction { super }

  def save!
    Post.transaction { super }

That's the workaround I'm going to use for now.

5 comment(s)


Peter Marklund said 2007-09-13 08:01:

Hah, thanks Jarkko, you're right, apparently Rails does wrap save and save! in transactions (the Transactions module in ActiveRecord). How embarrassing for me. I guess my RSpec specs were indicating that this was not the case and I didn't read the API doc or Rails code carefully. Many thanks for catching this! Jarkko - it's great to have you around to proof read my blog, otherwise there would be way too many inaccuracies lying around... See you soon in Berlin! Peter

Jon Griffin said 2007-09-10 17:39:

Thanks Peter, I am studying this now.

Peter Marklund said 2007-09-09 23:33:

Hi Jon! Thanks for the comment. I recommend that you switch to Rails and use PostgreSQL instead of MySQL. There are some nice plugins by Simon Harris related to foreign keys that you might want to use. I simply use the foreign key module prescribed in the Rails book. Regarding transactions you just have to be very aware of when they are used and when they are not. I think it's like Chad Fowler and others have been saying that ActiveRecord and Rails in general are leaky abstractions. There seems to be this hype and notion surrounding Rails that it makes web development so easy you hardly need programming skills any more to use it. This is simply not true. Sooner or later the abstractions are going to fall and you are going to hit the metal. At that point you need to understand at a deep level what's going on. This is true of web development in general, also if you use OpenACS. Another recommendation when/if you pick up Rails - accept the decisions and conventions that David has chosen for Rails, don't fight them. Coming from OpenACS I was at first trying to bring some of that baggage into Rails. These days I really try to stay with Rails conventions because I've seen how important that is, how it makes the code easier to maintain for me and for others.
-------------------------------------------------------------------------------- said 2007-09-09 21:09:

Peter, Coming from the real database world (and OACS), and just looking at ROR I really worry about how data unaware ROR is. A transaction is so important for data integrity I am not sure how anyone with a non MySQL background could deal with all of these "workarounds" You know from experience how to program a real relational model, what is your honest opinion of least common denominator database/application coding. I am really asking your opinion before I commit to changing from OpenACS. Thanks

Peter Marklund said 2007-09-06 08:35:

I needed transactions in multiple models so I came up with this: module SavesInTransaction def save self.class.transaction { super } end def save! self.class.transaction { super } end end