123456789_123456789_123456789_123456789_123456789_

Module: ActiveRecord::Transactions

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Included In:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Defined in: activerecord/lib/active_record/transactions.rb

Overview

See ClassMethods for documentation.

Constant Summary

Class Method Summary

::ActiveSupport::Concern - Extended

class_methods

Define class methods from given block.

included

Evaluate given block in context of base class, so that you can write class macros here.

prepended

Evaluate given block in context of base class, so that you can write class macros here.

append_features, prepend_features

Instance Attribute Summary

Instance Method Summary

DSL Calls

included

[ GitHub ]


10
11
12
13
14
# File 'activerecord/lib/active_record/transactions.rb', line 10

included do
  define_callbacks :commit, :rollback,
                   :before_commit,
                   scope: [:kind, :name]
end

Instance Attribute Details

#_committed_already_called (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 422

attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback

#_new_record_before_last_commit (rw)

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 16

attr_accessor :_new_record_before_last_commit # :nodoc:

#_trigger_destroy_callback (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 422

attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback

#_trigger_update_callback (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 422

attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback

#has_transactional_callbacks?Boolean (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 510

def has_transactional_callbacks?
  !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
end

#trigger_transactional_callbacks?Boolean (readonly)

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 416

def trigger_transactional_callbacks? # :nodoc:
  (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
    _trigger_destroy_callback && destroyed?
end

Instance Method Details

#add_to_transaction(ensure_finalize = true) (private)

Add the record to the current transaction so that the #after_rollback and #after_commit callbacks can be called.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 504

def add_to_transaction(ensure_finalize = true)
  self.class.with_connection do |connection|
    connection.add_transaction_record(self, ensure_finalize)
  end
end

#before_committed!

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 364

def before_committed! # :nodoc:
  _run_before_commit_callbacks
end

#clear_transaction_record_state (private)

Clear the new record state and id of a record.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 452

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

#committed!(should_run_callbacks: true)

This method is for internal use only.

Call the #after_commit callbacks.

Ensure that it is not called if the object was never persisted (failed create), but call it after the commit of a destroyed object.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 372

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

#destroy

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 348

def destroy # :nodoc:
  with_transaction_returning_status { super }
end

#init_internals (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 424

def init_internals
  super
  @_start_transaction_state = nil
  @_committed_already_called = nil
  @_new_record_before_last_commit = nil
end

#remember_transaction_record_state (private)

Save the new record state and id of a record so it can be restored later if a transaction fails.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 432

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

#restore_transaction_record_state(force_restore_state = false) (private)

Restore the new record state and id of a record that was previously saved by a call to save_record_state.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 459

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

#rolledback!(force_restore_state: false, should_run_callbacks: true)

This method is for internal use only.

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.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 384

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

#save

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 352

def save(**) # :nodoc:
  with_transaction_returning_status { super }
end

#save!

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 356

def save!(**) # :nodoc:
  with_transaction_returning_status { super }
end

#touch

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 360

def touch(*, **) # :nodoc:
  with_transaction_returning_status { super }
end

#transaction(**options, &block)

See Transactions::ClassMethods for detailed documentation.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 344

def transaction(**options, &block)
  self.class.transaction(**options, &block)
end

#transaction_include_any_action?(actions) ⇒ Boolean (private)

Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 489

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

#with_transaction_returning_status

Executes a block within a transaction and captures its return value as a status flag. If the status is true, the transaction is committed, otherwise a ROLLBACK is issued. In any case, the status flag is returned.

This method is available within the context of an Base instance.

[ GitHub ]

  
# File 'activerecord/lib/active_record/transactions.rb', line 400

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