Skip to content

Commit

Permalink
Allow to pass transaction options to the in_transaction helper
Browse files Browse the repository at this point in the history
This allows to use it as a replacement for the `ActiveRecord::Base.transaction`
  • Loading branch information
Envek committed Oct 28, 2022
1 parent 9e32dec commit 00554bf
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 5 deletions.
16 changes: 11 additions & 5 deletions lib/after_commit_everywhere.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,21 @@ def in_transaction?(connection = nil)

# Makes sure the provided block runs in a transaction. If we are not currently in a transaction, a new transaction is started.
#
# It mimics the ActiveRecord's +transaction+ method's API and actually uses it under the hood.
#
# However, the main difference is that it doesn't swallow +ActiveRecord::Rollback+ exception in case when there is no transaction open.
#
# @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-transaction
#
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] Database connection to operate in. Defaults to +ActiveRecord::Base.connection+
# @param requires_new [Boolean] Forces creation of new subtransaction (savepoint) even if transaction is already opened.
# @param new_tx_options [Hash<Symbol, void>] Options to be passed to +connection.transaction+ on new transaction creation
# @return void
def in_transaction(connection = nil)
connection ||= default_connection

if in_transaction?(connection)
def in_transaction(connection = default_connection, requires_new: false, **new_tx_options)
if in_transaction?(connection) && !requires_new
yield
else
connection.transaction { yield }
connection.transaction(requires_new: requires_new, **new_tx_options) { yield }
end
end

Expand Down
15 changes: 15 additions & 0 deletions spec/after_commit_everywhere_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,21 @@
end
end

it "runs new transaction even inside existing transaction if requires_new is true" do
outer_handler, inner_handler = spy("outter"), spy("inner")
expect(ActiveRecord::Base.connection.transaction_open?).to be_falsey
ActiveRecord::Base.transaction do
expect(ActiveRecord::Base.connection.transaction_open?).to be_truthy
described_class.after_commit { outer_handler.call }
receiver.in_transaction(requires_new: true) do
receiver.after_commit { inner_handler.call }
raise ActiveRecord::Rollback
end
end
expect(outer_handler).to have_received(:call)
expect(inner_handler).not_to have_received(:call)
end

context "when rolling back, the rollback propogates to the parent transaction block" do
subject { receiver.after_rollback { handler.call } }

Expand Down

0 comments on commit 00554bf

Please sign in to comment.