Module: AfterCommitEverywhere
- Defined in:
- lib/after_commit_everywhere.rb,
lib/after_commit_everywhere/wrap.rb,
lib/after_commit_everywhere/version.rb
Overview
Module allowing to use ActiveRecord transactional callbacks outside of ActiveRecord models, literally everywhere in your application.
Include it to your classes (e.g. your base service object class or whatever)
Defined Under Namespace
Classes: NotInTransaction, Wrap
Constant Summary collapse
- VERSION =
"1.1.0"
Class Method Summary collapse
-
.after_commit(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs
callbackafter successful commit of outermost transaction for databaseconnection. -
.after_rollback(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs
callbackafter rolling back of transaction or savepoint (if declared in nested transaction) for databaseconnection. -
.before_commit(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs
callbackbefore committing of outermost transaction forconnection. -
.in_transaction?(connection = ActiveRecord::Base.connection) ⇒ Boolean
Helper method to determine whether we’re currently in transaction or not.
- .register_callback(connection:, name:, no_tx_action:, callback:) ⇒ Object private
Class Method Details
.after_commit(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs callback after successful commit of outermost transaction for database connection.
If called outside transaction it will execute callback immediately.
28 29 30 31 32 33 34 35 |
# File 'lib/after_commit_everywhere.rb', line 28 def after_commit(connection: ActiveRecord::Base.connection, &callback) register_callback( connection: connection, name: __method__, callback: callback, no_tx_action: :execute, ) end |
.after_rollback(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs callback after rolling back of transaction or savepoint (if declared in nested transaction) for database connection.
Caveat: do not raise ActivRecord::Rollback in nested transaction block! See api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#module-ActiveRecord::Transactions::ClassMethods-label-Nested+transactions
69 70 71 72 73 74 75 76 |
# File 'lib/after_commit_everywhere.rb', line 69 def after_rollback(connection: ActiveRecord::Base.connection, &callback) register_callback( connection: connection, name: __method__, callback: callback, no_tx_action: :exception, ) end |
.before_commit(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs callback before committing of outermost transaction for connection.
If called outside transaction it will execute callback immediately.
Available only since Ruby on Rails 5.0. See github.com/rails/rails/pull/18936
46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/after_commit_everywhere.rb', line 46 def before_commit(connection: ActiveRecord::Base.connection, &callback) if ActiveRecord::VERSION::MAJOR < 5 raise NotImplementedError, "#{__method__} works only with Rails 5.0+" end register_callback( connection: connection, name: __method__, callback: callback, no_tx_action: :warn_and_execute, ) end |
.in_transaction?(connection = ActiveRecord::Base.connection) ⇒ Boolean
Helper method to determine whether we’re currently in transaction or not
98 99 100 101 |
# File 'lib/after_commit_everywhere.rb', line 98 def in_transaction?(connection = ActiveRecord::Base.connection) # service transactions (tests and database_cleaner) are not joinable connection.transaction_open? && connection.current_transaction.joinable? end |
.register_callback(connection:, name:, no_tx_action:, callback:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/after_commit_everywhere.rb', line 79 def register_callback(connection:, name:, no_tx_action:, callback:) raise ArgumentError, "Provide callback to #{name}" unless callback unless in_transaction?(connection) case no_tx_action when :warn_and_execute warn "#{name}: No transaction open. Executing callback immediately." return callback.call when :execute return callback.call when :exception raise NotInTransaction, "#{name} is useless outside transaction" end end wrap = Wrap.new(connection: connection, "#{name}": callback) connection.add_transaction_record(wrap) end |