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
- RAISE =
Causes before_commit and after_commit to raise an exception when called outside a transaction.
:raise
- EXECUTE =
Causes before_commit and after_commit to execute the given callback immediately when called outside a transaction.
:execute
- WARN_AND_EXECUTE =
Causes before_commit and after_commit to log a warning before calling the given callback immediately when called outside a transaction.
:warn_and_execute
- VERSION =
"1.2.0"
Class Method Summary collapse
-
.after_commit(connection: ActiveRecord::Base.connection, without_tx: EXECUTE, &callback) ⇒ Object
Runs
callback
after successful commit of outermost transaction for databaseconnection
. -
.after_rollback(connection: ActiveRecord::Base.connection, &callback) ⇒ Object
Runs
callback
after rolling back of transaction or savepoint (if declared in nested transaction) for databaseconnection
. -
.before_commit(connection: ActiveRecord::Base.connection, without_tx: WARN_AND_EXECUTE, &callback) ⇒ Object
Runs
callback
before 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:, without_tx:, callback:) ⇒ Object private
Class Method Details
.after_commit(connection: ActiveRecord::Base.connection, without_tx: EXECUTE, &callback) ⇒ Object
Runs callback
after successful commit of outermost transaction for database connection
.
41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/after_commit_everywhere.rb', line 41 def after_commit( connection: ActiveRecord::Base.connection, without_tx: EXECUTE, &callback ) register_callback( connection: connection, name: __method__, callback: callback, without_tx: without_tx, ) 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
93 94 95 96 97 98 99 100 |
# File 'lib/after_commit_everywhere.rb', line 93 def after_rollback(connection: ActiveRecord::Base.connection, &callback) register_callback( connection: connection, name: __method__, callback: callback, without_tx: RAISE, ) end |
.before_commit(connection: ActiveRecord::Base.connection, without_tx: WARN_AND_EXECUTE, &callback) ⇒ Object
Runs callback
before committing of outermost transaction for connection
.
Available only since Ruby on Rails 5.0. See github.com/rails/rails/pull/18936
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/after_commit_everywhere.rb', line 66 def before_commit( connection: ActiveRecord::Base.connection, without_tx: WARN_AND_EXECUTE, &callback ) if ActiveRecord::VERSION::MAJOR < 5 raise NotImplementedError, "#{__method__} works only with Rails 5.0+" end register_callback( connection: connection, name: __method__, callback: callback, without_tx: without_tx, ) end |
.in_transaction?(connection = ActiveRecord::Base.connection) ⇒ Boolean
Helper method to determine whether we’re currently in transaction or not
124 125 126 127 |
# File 'lib/after_commit_everywhere.rb', line 124 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:, without_tx:, 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.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/after_commit_everywhere.rb', line 103 def register_callback(connection:, name:, without_tx:, callback:) raise ArgumentError, "Provide callback to #{name}" unless callback unless in_transaction?(connection) case without_tx when WARN_AND_EXECUTE warn "#{name}: No transaction open. Executing callback immediately." return callback.call when EXECUTE return callback.call when RAISE raise NotInTransaction, "#{name} is useless outside transaction" else raise ArgumentError, "Invalid \"without_tx\": \"#{without_tx}\"" end end wrap = Wrap.new(connection: connection, "#{name}": callback) connection.add_transaction_record(wrap) end |