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.with_connection do |connection| connection.add_transaction_record(self, ensure_finalize) end 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 init_internals
def init_internals super @_start_transaction_state = nil @_committed_already_called = nil @_new_record_before_last_commit = nil 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 self.class.composite_primary_key? if restore_state[:id] != @primary_key.map { |col| @attributes.fetch_value(col) } @primary_key.zip(restore_state[:id]).each do |col, val| @attributes.write_from_user(col, val) end end else if @attributes.fetch_value(@primary_key) != restore_state[:id] @attributes.write_from_user(@primary_key, restore_state[:id]) end 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
otherwise a ROLLBACK is issued. In any case, the status flag is returned.
status flag. If the status is true, the transaction is committed,
Executes a block within a transaction and captures its return value as a
def with_transaction_returning_status self.class.with_connection do |connection| status = nil 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 end