module ActiveRecord::Transactions
def add_to_transaction(ensure_finalize = true)
Add the record to the current transaction so that the #after_rollback and #after_commit
def add_to_transaction(ensure_finalize = true) self.class.connection.add_transaction_record(self, ensure_finalize) end
def before_committed! # :nodoc:
def before_committed! # :nodoc: _run_before_commit_callbacks end
def clear_transaction_record_state
def clear_transaction_record_state return unless @_start_transaction_state @_start_transaction_state[:level] -= 1 @_start_transaction_state = nil if @_start_transaction_state[:level] < 1 end
def committed!(should_run_callbacks: true) # :nodoc:
but call it after the commit of a destroyed object.
Ensure that it is not called if the object was never persisted (failed create),
Call the #after_commit callbacks.
def committed!(should_run_callbacks: true) # :nodoc: @_start_transaction_state = nil if should_run_callbacks @_committed_already_called = true _run_commit_callbacks end ensure @_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false end
def destroy # :nodoc:
def destroy # :nodoc: with_transaction_returning_status { super } end
def has_transactional_callbacks?
def has_transactional_callbacks? !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty? end
def remember_transaction_record_state
def remember_transaction_record_state @_start_transaction_state ||= { id: id, new_record: @new_record, previously_new_record: @previously_new_record, destroyed: @destroyed, attributes: @attributes, frozen?: frozen?, level: 0 } @_start_transaction_state[:level] += 1 if _committed_already_called @_new_record_before_last_commit = false else @_new_record_before_last_commit = @_start_transaction_state[:new_record] end end
def restore_transaction_record_state(force_restore_state = false)
def restore_transaction_record_state(force_restore_state = false) if restore_state = @_start_transaction_state if force_restore_state || restore_state[:level] <= 1 @new_record = restore_state[:new_record] @previously_new_record = restore_state[:previously_new_record] @destroyed = restore_state[:destroyed] @attributes = restore_state[:attributes].map do |attr| value = @attributes.fetch_value(attr.name) attr = attr.with_value_from_user(value) if attr.value != value attr end @mutations_from_database = nil @mutations_before_last_save = nil if @attributes.fetch_value(@primary_key) != restore_state[:id] @attributes.write_from_user(@primary_key, restore_state[:id]) end freeze if restore_state[:frozen?] end end end
def rolledback!(force_restore_state: false, should_run_callbacks: true) # :nodoc:
state should be rolled back to the beginning or just to the last savepoint.
Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
def rolledback!(force_restore_state: false, should_run_callbacks: true) # :nodoc: if should_run_callbacks _run_rollback_callbacks end ensure restore_transaction_record_state(force_restore_state) clear_transaction_record_state @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state end
def save(**) # :nodoc:
def save(**) # :nodoc: with_transaction_returning_status { super } end
def save!(**) # :nodoc:
def save!(**) # :nodoc: with_transaction_returning_status { super } end
def touch(*, **) # :nodoc:
def touch(*, **) # :nodoc: with_transaction_returning_status { super } end
def transaction(**options, &block)
def transaction(**options, &block) self.class.transaction(**options, &block) end
def transaction_include_any_action?(actions)
def transaction_include_any_action?(actions) actions.any? do |action| case action when :create persisted? && @_new_record_before_last_commit when :update !(@_new_record_before_last_commit || destroyed?) && _trigger_update_callback when :destroy _trigger_destroy_callback end end end
def trigger_transactional_callbacks? # :nodoc:
def trigger_transactional_callbacks? # :nodoc: (@_new_record_before_last_commit || _trigger_update_callback) && persisted? || _trigger_destroy_callback && destroyed? end
def with_transaction_returning_status
This method is available within the context of an ActiveRecord::Base
a ROLLBACK is issued. In any case the status flag is returned.
status flag. If the status is true the transaction is committed, otherwise
Executes +method+ within a transaction and captures its return value as a
def with_transaction_returning_status status = nil connection = self.class.connection ensure_finalize = !connection.transaction_open? connection.transaction do add_to_transaction(ensure_finalize || has_transactional_callbacks?) remember_transaction_record_state status = yield raise ActiveRecord::Rollback unless status end status end