Do something only after the currently open transactions have finished.
Normally everything gets rolled back when a transaction fails, but you cannot roll back sending an email or adding a job to Resque.
Install
gem install ar_after_transaction
Usage
just-in-time callbacks
class User
after_create :do_stuff, :oops
def do_stuff
after_transaction do
send_an_email # cannot be rolled back
end
comments.create(...) # will be rolled back
end
def oops
raise "do the rolback!"
end
end
General 'this should be rolled back when in a transaction' code like jobs
class Resque
def revertable_enqueue(*args)
ActiveRecord::Base.after_transaction do
enqueue(*args)
end
end
end
When not in a transaction
after_transaction will perform the given block immediately
Transactional fixtures <-> normally_open_transactions
after_transaction assumes zero open transactions.
If you use transactional fixtures you should change it in test mode.
Rspec:
# spec/rails_helper.rb
config.before(:suite) do
ActiveRecord::Base.normally_open_transactions = 1
end
Adding new rails versions
- bump in
ar_after_transaction.gemspec
- create a new gemfiles/.gemfile
BUNDLE_GEMFILE=gemfiles/<new>.gemfile bundle
BUNDLE_GEMFILE=gemfiles/<new>.gemfile bundle exec rake
- update
.github/workflows/actions.yml
- make a PR
Alternative
Rails 3+
- basic support is built in, use it if you can!
after_commit :foo
after_commit :bar, on: :create / :update
- after_commit everywhere
- pro: threadsafe
- pro: more fine-grained callbacks (before_commit,
after_commit
, before_rollback, after_rollback)
- con: doesn't let you define
after_transaction
callbacks anywhere likear_after_transaction
does (outside of theafter_commit
, etc. callbacks which only happen at certain points in the model's life cycle)
- con: more complex
Authors
Original idea and code from Jamis Buck (post by Jeremy Kemper)
- Bogdan Gusiev
- Benedikt Deicke
- Tyler Rick
- Michael Wu
- C.W.
- Ben Weintraub
- Vladimir Temnikov
- Mark Gangl
- Alex Vondrak
Michael Grosser
michael@grosser.it
License: MIT