Class: ActiveRecord::ConnectionAdapters::Transaction
Do not use. This class is for internal use only.
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Inherits: | Object |
Defined in: | activerecord/lib/active_record/connection_adapters/abstract/transaction.rb |
Class Method Summary
Instance Attribute Summary
- #closed? ⇒ Boolean readonly
- #connection readonly
- #dirty? ⇒ Boolean readonly
- #full_rollback? ⇒ Boolean readonly
- #isolation_level readonly
- #joinable? ⇒ Boolean readonly
- #materialized? ⇒ Boolean readonly
- #open? ⇒ Boolean readonly
-
#restartable? ⇒ Boolean
readonly
Can this transaction’s current state be recreated by rollback+begin ?
- #savepoint_name readonly
- #state readonly
- #user_transaction readonly
- #written rw
Instance Method Summary
- #add_record(record, ensure_finalize = true)
- #after_commit(&block)
- #after_rollback(&block)
- #before_commit(&block)
- #before_commit_records
- #commit_records
- #dirty!
- #incomplete!
- #invalidate!
- #invalidated? ⇒ Boolean
- #materialize!
- #records
- #restore!
- #rollback_records
- #append_callbacks(callbacks) protected
- #prepare_instances_to_run_callbacks_on(records) private
- #run_action_on_records(records, instances_to_run_callbacks_on) private
- #unique_records private
Constructor Details
.new(connection, isolation: nil, joinable: true, run_commit_callbacks: false) ⇒ Transaction
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 153
def initialize(connection, isolation: nil, joinable: true, run_commit_callbacks: false) super() @connection = connection @state = TransactionState.new @callbacks = nil @records = nil @isolation_level = isolation @materialized = false @joinable = joinable @run_commit_callbacks = run_commit_callbacks @lazy_enrollment_records = nil @dirty = false @user_transaction = joinable ? ActiveRecord::Transaction.new(self) : ActiveRecord::Transaction::NULL_TRANSACTION @instrumenter = TransactionInstrumenter.new(connection: connection, transaction: @user_transaction) end
Instance Attribute Details
#closed? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 181
def closed? false end
#connection (readonly)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 148
attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
#dirty? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 173
def dirty? @dirty end
#full_rollback? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 327
def full_rollback?; true; end
#isolation_level (readonly)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 148
attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
#joinable? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 328
def joinable?; @joinable; end
#materialized? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 242
def materialized? @materialized end
#open? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 177
def open? true end
#restartable? ⇒ Boolean
(readonly)
Can this transaction’s current state be recreated by rollback+begin ?
#savepoint_name (readonly)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 148
attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
#state (readonly)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 148
attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
#user_transaction (readonly)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 148
attr_reader :connection, :state, :savepoint_name, :isolation_level, :user_transaction
#written (rw)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 149
attr_accessor :written
Instance Method Details
#add_record(record, ensure_finalize = true)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 185
def add_record(record, ensure_finalize = true) @records ||= [] if ensure_finalize @records << record else @lazy_enrollment_records ||= ObjectSpace::WeakMap.new @lazy_enrollment_records[record] = record end end
#after_commit(&block)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 203
def after_commit(&block) if @state.finalized? raise ActiveRecordError, "Cannot register callbacks on a finalized transaction" end (@callbacks ||= []) << Callback.new(:after_commit, block) end
#after_rollback(&block)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 211
def after_rollback(&block) if @state.finalized? raise ActiveRecordError, "Cannot register callbacks on a finalized transaction" end (@callbacks ||= []) << Callback.new(:after_rollback, block) end
#append_callbacks(callbacks) (protected)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 331
def append_callbacks(callbacks) # :nodoc: (@callbacks ||= []).concat(callbacks) end
#before_commit(&block)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 195
def before_commit(&block) if @state.finalized? raise ActiveRecordError, "Cannot register callbacks on a finalized transaction" end (@callbacks ||= []) << Callback.new(:before_commit, block) end
#before_commit_records
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 274
def before_commit_records if @run_commit_callbacks if records if ActiveRecord.before_committed_on_all_records ite = unique_records instances_to_run_callbacks_on = records.each_with_object({}) do |record, candidates| candidates[record] = record end run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks| record.before_committed! if should_run_callbacks end else records.uniq.each(&:before_committed!) end end @callbacks&.each(&:before_commit) end # Note: When @run_commit_callbacks is false #commit_records takes care of appending # remaining callbacks to the parent transaction end
#commit_records
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 298
def commit_records if records begin ite = unique_records if @run_commit_callbacks instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite) run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks| record.committed!(should_run_callbacks: should_run_callbacks) end else while record = ite.shift # if not running callbacks, only adds the record to the parent transaction connection.add_transaction_record(record) end end ensure ite&.each { |i| i.committed!(should_run_callbacks: false) } end end if @run_commit_callbacks @callbacks&.each(&:after_commit) elsif @callbacks connection.current_transaction.append_callbacks(@callbacks) end end
#dirty!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 169
def dirty! @dirty = true end
#incomplete!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 233
def incomplete! @instrumenter.finish(:incomplete) if materialized? end
#invalidate!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 151
delegate :invalidate!, :invalidated?, to: :@state
#invalidated? ⇒ Boolean
# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 151
delegate :invalidate!, :invalidated?, to: :@state
#materialize!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 237
def materialize! @materialized = true @instrumenter.start end
#prepare_instances_to_run_callbacks_on(records) (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 348
def prepare_instances_to_run_callbacks_on(records) records.each_with_object({}) do |record, candidates| next unless record.trigger_transactional_callbacks? earlier_saved_candidate = candidates[record] next if earlier_saved_candidate && record.class.run_commit_callbacks_on_first_saved_instances_in_transaction # If the candidate instance destroyed itself in the database, then # instances which were added to the transaction afterwards, and which # think they updated themselves, are wrong. They should not replace # our candidate as an instance to run callbacks on next if earlier_saved_candidate&.destroyed? && !record.destroyed? # If the candidate instance was created inside of this transaction, # then instances which were subsequently loaded from the database # and updated need that state transferred to them so that # the after_create_commit callbacks are run record._new_record_before_last_commit = true if earlier_saved_candidate&._new_record_before_last_commit # The last instance to save itself is likeliest to have internal # state that matches what's committed to the database candidates[record] = record end end
#records
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 219
def records if @lazy_enrollment_records @records.concat @lazy_enrollment_records.values @lazy_enrollment_records = nil end @records end
#restore!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 246
def restore! if materialized? incomplete! @materialized = false materialize! end end
#rollback_records
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 254
def rollback_records if records begin ite = unique_records instances_to_run_callbacks_on = prepare_instances_to_run_callbacks_on(ite) run_action_on_records(ite, instances_to_run_callbacks_on) do |record, should_run_callbacks| record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks) end ensure ite&.each do |i| i.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: false) end end end @callbacks&.each(&:after_rollback) end
#run_action_on_records(records, instances_to_run_callbacks_on) (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 340
def run_action_on_records(records, instances_to_run_callbacks_on) while record = records.shift should_run_callbacks = record.__id__ == instances_to_run_callbacks_on[record].__id__ yield record, should_run_callbacks end end
#unique_records (private)
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb', line 336
def unique_records records.uniq(&:__id__) end