In an application I wrote for a client I needed transactions to handle a batch import of records from a legacy table into different models.
I browsed the documentation, googled for info and even asked in #rubyonrails, but wasn’t able to get any help, so I had to resort to good old trial and error.
First I tried nested transactions (the old way):
FirstModel.transaction do SecondModel.transaction do ThirdModel.transaction do FourthModel.transaction do fourth.do_stuff third.save second.handle_your_stuff first.good_old_foo_bar end end end end
I had a couple of problems with this code:
It also didn’t seem to work for me, so I banged my head against my laptop for half a hour or so and suddenly the rails documentation started to make sense, so I wrote this code instead:
transaction do first.save! second.save! third.save! fourth.save! end
The reason I used save! was that the documentation says that a transaction block catches exceptions. Unfortunately that’s not true and to make it work I had to remove the exclamation marks.
Now I had another problem. I included the transaction code in a class I put in lib/, ImportJob, and I was using it with script/runner:
script/runner 'ImportJob.run' -e ENVIRONMENT
All of a sudden I started getting method missing errors on transaction. Now I could investigate and do the right thing or just hack a solution – I decided to hack a solution
class ImportJob < ActiveRecord::Migration end
Deriving ImportJob from Migration solved my problems. Now if anyone has a cleaner solution I will be happy to implement it but at least I solved my problem with transactions (and I hope this will be helpful for someone else too).
Update: Tim pointed out some flaws in my code and some more testing revealed that I needed to have an exception to trigger a Rollback, so I modified the block:
begin transaction do first.save! second.save! third.save! fourth.save! end rescue ActiveRecord::RecordInvalid => invalid # do whatever you wish to warn the user, or log something end
This works fine, thanks Tim!
6 Responses to “Transaction in Rails”