Coupling rollback actions with transaction actions

The system I’m currently developing needs to import a variety of data from another system. The data arrives in batches, and within a batch some items might be valid and some might be invalid – I expect that this is a common problem. An item in the batch might also update many different objects within my domain model, and I won’t necessarily know if the item is invalid until I try to commit the changes to the domain model. It became fairly clear that I had some recurring code patterns in my application, so of course I wanted to extract them into some abstraction and Ruby’s reflection gave me a nice way to capture this.

What I needed was to be able to associate a piece of code that created or modified some domain objects with the code that cleaned up the changes to the domain model on rollback (assuming that the database transaction handled the persistence parts). I could have used blocks, but I find that unlabelled blocks aren’t very expressive so I decided to use methods (and their names) instead of blocks. Here’s an example of using my method, #within_transaction_with_rollback; in the example :create_reference_objects and :clear_reference_objects are methods defined somewhere else in the class.


  def process
    within_transaction_with_rollback(:create_reference_objects, :clear_reference_objects)
  end

And here’s the implementation of my method, for those who are interested. I’m sure that there are plenty of other possible implementations :-)


module Transactions

    def within_transaction_with_rollback(transaction_method, rollback_method)
      begin
        within_transaction(transaction_method)
      rescue
        self.send(rollback_method)
      end
    end

    def within_transaction(create_method)
      self.class.transaction do
        self.send(create_method)
      end
    end

end

~ by Steve Hayes on February 22, 2008.

Leave a Reply