aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/transactions.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/transactions.rb')
-rw-r--r--activerecord/lib/active_record/transactions.rb54
1 files changed, 34 insertions, 20 deletions
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index c33ffeece0..f92e1de03b 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -1,15 +1,25 @@
-require 'thread'
-
module ActiveRecord
# See ActiveRecord::Transactions::ClassMethods for documentation.
module Transactions
extend ActiveSupport::Concern
ACTIONS = [:create, :destroy, :update]
+ CALLBACK_WARN_MESSAGE = "Currently, Active Record suppresses errors raised " \
+ "within `after_rollback`/`after_commit` callbacks and only print them to " \
+ "the logs. In the next version, these errors will no longer be suppressed. " \
+ "Instead, the errors will propagate normally just like in other Active " \
+ "Record callbacks.\n" \
+ "\n" \
+ "You can opt into the new behavior and remove this warning by setting:\n" \
+ "\n" \
+ " config.active_record.raise_in_transactional_callbacks = true\n\n"
included do
define_callbacks :commit, :rollback,
terminator: ->(_, result) { result == false },
scope: [:kind, :name]
+
+ mattr_accessor :raise_in_transactional_callbacks, instance_writer: false
+ self.raise_in_transactional_callbacks = false
end
# = Active Record Transactions
@@ -225,6 +235,9 @@ module ActiveRecord
def after_commit(*args, &block)
set_options_for_callbacks!(args)
set_callback(:commit, :after, *args, &block)
+ unless ActiveRecord::Base.raise_in_transactional_callbacks
+ ActiveSupport::Deprecation.warn(CALLBACK_WARN_MESSAGE)
+ end
end
# This callback is called after a create, update, or destroy are rolled back.
@@ -233,6 +246,9 @@ module ActiveRecord
def after_rollback(*args, &block)
set_options_for_callbacks!(args)
set_callback(:rollback, :after, *args, &block)
+ unless ActiveRecord::Base.raise_in_transactional_callbacks
+ ActiveSupport::Deprecation.warn(CALLBACK_WARN_MESSAGE)
+ end
end
private
@@ -292,16 +308,16 @@ module ActiveRecord
#
# Ensure that it is not called if the object was never persisted (failed create),
# but call it after the commit of a destroyed object.
- def committed! #:nodoc:
- run_callbacks :commit if destroyed? || persisted?
+ def committed!(should_run_callbacks = true) #:nodoc:
+ _run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
ensure
- clear_transaction_record_state
+ force_clear_transaction_record_state
end
# Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
# state should be rolled back to the beginning or just to the last savepoint.
- def rolledback!(force_restore_state = false) #:nodoc:
- run_callbacks :rollback
+ def rolledback!(force_restore_state = false, should_run_callbacks = true) #:nodoc:
+ _run_rollback_callbacks if should_run_callbacks
ensure
restore_transaction_record_state(force_restore_state)
clear_transaction_record_state
@@ -328,7 +344,7 @@ module ActiveRecord
begin
status = yield
rescue ActiveRecord::Rollback
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ clear_transaction_record_state
status = nil
end
@@ -341,7 +357,7 @@ module ActiveRecord
# Save the new record state and id of a record so it can be restored later if a transaction fails.
def remember_transaction_record_state #:nodoc:
- @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
+ @_start_transaction_state[:id] = id
unless @_start_transaction_state.include?(:new_record)
@_start_transaction_state[:new_record] = @new_record
end
@@ -349,13 +365,18 @@ module ActiveRecord
@_start_transaction_state[:destroyed] = @destroyed
end
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
- @_start_transaction_state[:frozen?] = @attributes.frozen?
+ @_start_transaction_state[:frozen?] = frozen?
end
# Clear the new record state and id of a record.
def clear_transaction_record_state #:nodoc:
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
- @_start_transaction_state.clear if @_start_transaction_state[:level] < 1
+ force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
+ end
+
+ # Force to clear the transaction record state.
+ def force_clear_transaction_record_state #:nodoc:
+ @_start_transaction_state.clear
end
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
@@ -364,17 +385,10 @@ module ActiveRecord
transaction_level = (@_start_transaction_state[:level] || 0) - 1
if transaction_level < 1 || force
restore_state = @_start_transaction_state
- was_frozen = restore_state[:frozen?]
- @attributes = @attributes.dup if @attributes.frozen?
+ thaw unless restore_state[:frozen?]
@new_record = restore_state[:new_record]
@destroyed = restore_state[:destroyed]
- if restore_state.has_key?(:id)
- self.id = restore_state[:id]
- else
- @attributes.delete(self.class.primary_key)
- @attributes_cache.delete(self.class.primary_key)
- end
- @attributes.freeze if was_frozen
+ write_attribute(self.class.primary_key, restore_state[:id])
end
end
end