When you use Ruby on Rails with ActiveRecord, you can get used to having separate transaction on each request. This is valid also when using Trailblazer (when inside of a request scope), however Trailblazer on its own does not provide such functionality. It means that when you’re using it from the console and/or when you process stuff inside background workers, you no longer have an active transaction wrapping around an operation.

This behavior is good most of the time. Since background tasks can run for a long period of time, there might be a risk of unintentional locking a big part of your database. However, sometimes you just need to have transactions.

In order to provide this feature for each operation, we will use a concern that will include that logic. We will also make it configurable, so if we inherit from a given operation, we will still have an option to disable/enable transaction support based on the operation requirements.

The code itself is pretty simple – it will just wraps around a #run method of the operation class with a transaction (as long as transaction support is enabled). Note, that by default transactional flag is set to false.

module Concerns
module Transactional
extend ActiveSupport::Concern
included do
class_attribute :transactional
self.transactional = false
end
def run
if self.class.transactional
self.class.transaction do
super
end
else
super
end
end
class_methods do
def transaction
ActiveRecord::Base.transaction do
return yield
end
end
end
end
end

In order to use it, just include it into your operation:

class ApplicationOperation < Trailblazer::Operation
# Including on its own won't turn transactions on
include Concerns::Transactional
end
class DataOperation < ApplicationOperation
# This operation will have a single transaction wrapping it around
self.transactional = true
end