Revert "Temporarily revert "Update after_commit and after_rollback docs and tests to use new style API with an :on options instead of on_* suffix." and "Add after_commit and after_rollback callbacks to ActiveRecord that are called after transactions either commit or rollback on all records saved or destroyed in the transaction.""
This reverts commit 1b2941cba1165b0721f57524645fe378bee2a950. [#2991]
This commit is contained in:
parent
87cc3d5569
commit
b070739240
@ -14,6 +14,8 @@
|
||||
|
||||
* find_or_create_by_attr(value, ...) works when attr is protected. #4457 [Santiago Pastorino, Marc-André Lafortune]
|
||||
|
||||
* New callbacks: after_commit and after_rollback. Do expensive operations like image thumbnailing after_commit instead of after_save. #2991 [Brian Durand]
|
||||
|
||||
* Serialized attributes are not converted to YAML if they are any of the formats that can be serialized to XML (like Hash, Array and Strings). [José Valim]
|
||||
|
||||
* Destroy uses optimistic locking. If lock_version on the record you're destroying doesn't match lock_version in the database, a StaleObjectError is raised. #1966 [Curtis Hawthorne]
|
||||
|
@ -122,6 +122,8 @@ def transaction(options = {})
|
||||
requires_new = options[:requires_new] || !last_transaction_joinable
|
||||
|
||||
transaction_open = false
|
||||
@_current_transaction_records ||= []
|
||||
|
||||
begin
|
||||
if block_given?
|
||||
if requires_new || open_transactions == 0
|
||||
@ -132,6 +134,7 @@ def transaction(options = {})
|
||||
end
|
||||
increment_open_transactions
|
||||
transaction_open = true
|
||||
@_current_transaction_records.push([])
|
||||
end
|
||||
yield
|
||||
end
|
||||
@ -141,8 +144,10 @@ def transaction(options = {})
|
||||
decrement_open_transactions
|
||||
if open_transactions == 0
|
||||
rollback_db_transaction
|
||||
rollback_transaction_records(true)
|
||||
else
|
||||
rollback_to_savepoint
|
||||
rollback_transaction_records(false)
|
||||
end
|
||||
end
|
||||
raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
|
||||
@ -157,20 +162,35 @@ def transaction(options = {})
|
||||
begin
|
||||
if open_transactions == 0
|
||||
commit_db_transaction
|
||||
commit_transaction_records
|
||||
else
|
||||
release_savepoint
|
||||
save_point_records = @_current_transaction_records.pop
|
||||
unless save_point_records.blank?
|
||||
@_current_transaction_records.push([]) if @_current_transaction_records.empty?
|
||||
@_current_transaction_records.last.concat(save_point_records)
|
||||
end
|
||||
end
|
||||
rescue Exception => database_transaction_rollback
|
||||
if open_transactions == 0
|
||||
rollback_db_transaction
|
||||
rollback_transaction_records(true)
|
||||
else
|
||||
rollback_to_savepoint
|
||||
rollback_transaction_records(false)
|
||||
end
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
||||
# can be called.
|
||||
def add_transaction_record(record)
|
||||
last_batch = @_current_transaction_records.last
|
||||
last_batch << record if last_batch
|
||||
end
|
||||
|
||||
# Begins the transaction (and turns off auto-committing).
|
||||
def begin_db_transaction() end
|
||||
|
||||
@ -268,6 +288,42 @@ def sanitize_limit(limit)
|
||||
limit.to_i
|
||||
end
|
||||
end
|
||||
|
||||
# Send a rollback message to all records after they have been rolled back. If rollback
|
||||
# is false, only rollback records since the last save point.
|
||||
def rollback_transaction_records(rollback) #:nodoc
|
||||
if rollback
|
||||
records = @_current_transaction_records.flatten
|
||||
@_current_transaction_records.clear
|
||||
else
|
||||
records = @_current_transaction_records.pop
|
||||
end
|
||||
|
||||
unless records.blank?
|
||||
records.uniq.each do |record|
|
||||
begin
|
||||
record.rolledback!(rollback)
|
||||
rescue Exception => e
|
||||
record.logger.error(e) if record.respond_to?(:logger)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Send a commit message to all records after they have been committed.
|
||||
def commit_transaction_records #:nodoc
|
||||
records = @_current_transaction_records.flatten
|
||||
@_current_transaction_records.clear
|
||||
unless records.blank?
|
||||
records.uniq.each do |record|
|
||||
begin
|
||||
record.committed!
|
||||
rescue Exception => e
|
||||
record.logger.error(e) if record.respond_to?(:logger)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -8,6 +8,11 @@ module Transactions
|
||||
class TransactionError < ActiveRecordError # :nodoc:
|
||||
end
|
||||
|
||||
included do
|
||||
define_model_callbacks :commit, :commit_on_update, :commit_on_create, :commit_on_destroy, :only => :after
|
||||
define_model_callbacks :rollback, :rollback_on_update, :rollback_on_create, :rollback_on_destroy
|
||||
end
|
||||
|
||||
# Transactions are protective blocks where SQL statements are only permanent
|
||||
# if they can all succeed as one atomic action. The classic example is a
|
||||
# transfer between two accounts where you can only have a deposit if the
|
||||
@ -158,6 +163,21 @@ class TransactionError < ActiveRecordError # :nodoc:
|
||||
# http://dev.mysql.com/doc/refman/5.0/en/savepoints.html
|
||||
# for more information about savepoints.
|
||||
#
|
||||
# === Callbacks
|
||||
#
|
||||
# There are two types of callbacks associated with committing and rolling back transactions:
|
||||
# +after_commit+ and +after_rollback+.
|
||||
#
|
||||
# +after_commit+ callbacks are called on every record saved or destroyed within a
|
||||
# transaction immediately after the transaction is committed. +after_rollback+ callbacks
|
||||
# are called on every record saved or destroyed within a transaction immediately after the
|
||||
# transaction or savepoint is rolled back.
|
||||
#
|
||||
# These callbacks are useful for interacting with other systems since you will be guaranteed
|
||||
# that the callback is only executed when the database is in a permanent state. For example,
|
||||
# +after_commit+ is a good spot to put in a hook to clearing a cache since clearing it from
|
||||
# within a transaction could trigger the cache to be regenerated before the database is updated.
|
||||
#
|
||||
# === Caveats
|
||||
#
|
||||
# If you're on MySQL, then do not use DDL operations in nested transactions
|
||||
@ -205,19 +225,50 @@ def save!(*) #:nodoc:
|
||||
|
||||
# Reset id and @new_record if the transaction rolls back.
|
||||
def rollback_active_record_state!
|
||||
id_present = has_attribute?(self.class.primary_key)
|
||||
previous_id = id
|
||||
previous_new_record = new_record?
|
||||
remember_transaction_record_state
|
||||
yield
|
||||
rescue Exception
|
||||
@new_record = previous_new_record
|
||||
if id_present
|
||||
self.id = previous_id
|
||||
else
|
||||
@attributes.delete(self.class.primary_key)
|
||||
@attributes_cache.delete(self.class.primary_key)
|
||||
end
|
||||
restore_transaction_record_state
|
||||
raise
|
||||
ensure
|
||||
clear_transaction_record_state
|
||||
end
|
||||
|
||||
# Call the after_commit callbacks
|
||||
def committed! #:nodoc:
|
||||
if transaction_record_state(:new_record)
|
||||
_run_commit_on_create_callbacks
|
||||
elsif transaction_record_state(:destroyed)
|
||||
_run_commit_on_destroy_callbacks
|
||||
else
|
||||
_run_commit_on_update_callbacks
|
||||
end
|
||||
_run_commit_callbacks
|
||||
ensure
|
||||
clear_transaction_record_state
|
||||
end
|
||||
|
||||
# Call the after rollback callbacks. The 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:
|
||||
if transaction_record_state(:new_record)
|
||||
_run_rollback_on_create_callbacks
|
||||
elsif transaction_record_state(:destroyed)
|
||||
_run_rollback_on_destroy_callbacks
|
||||
else
|
||||
_run_rollback_on_update_callbacks
|
||||
end
|
||||
_run_rollback_callbacks
|
||||
ensure
|
||||
restore_transaction_record_state(force_restore_state)
|
||||
end
|
||||
|
||||
# Add the record to the current transaction so that the :after_rollback and :after_commit callbacks
|
||||
# can be called.
|
||||
def add_to_transaction
|
||||
if self.class.connection.add_transaction_record(self)
|
||||
remember_transaction_record_state
|
||||
end
|
||||
end
|
||||
|
||||
# Executes +method+ within a transaction and captures its return value as a
|
||||
@ -229,10 +280,59 @@ def rollback_active_record_state!
|
||||
def with_transaction_returning_status
|
||||
status = nil
|
||||
self.class.transaction do
|
||||
add_to_transaction
|
||||
status = yield
|
||||
raise ActiveRecord::Rollback unless status
|
||||
end
|
||||
status
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# 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 ||= {}
|
||||
unless @_start_transaction_state.include?(:new_record)
|
||||
@_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
|
||||
@_start_transaction_state[:new_record] = @new_record
|
||||
end
|
||||
unless @_start_transaction_state.include?(:destroyed)
|
||||
@_start_transaction_state[:destroyed] = @new_record
|
||||
end
|
||||
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
|
||||
end
|
||||
|
||||
# Clear the new record state and id of a record.
|
||||
def clear_transaction_record_state #:nodoc
|
||||
if defined?(@_start_transaction_state)
|
||||
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
|
||||
remove_instance_variable(:@_start_transaction_state) if @_start_transaction_state[:level] < 1
|
||||
end
|
||||
end
|
||||
|
||||
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
|
||||
def restore_transaction_record_state(force = false) #:nodoc
|
||||
if defined?(@_start_transaction_state)
|
||||
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
|
||||
if @_start_transaction_state[:level] < 1
|
||||
restore_state = remove_instance_variable(:@_start_transaction_state)
|
||||
if restore_state
|
||||
@new_record = restore_state[:new_record]
|
||||
@destroyed = restore_state[:destroyed]
|
||||
if restore_state[:id]
|
||||
self.id = restore_state[:id]
|
||||
else
|
||||
@attributes.delete(self.class.primary_key)
|
||||
@attributes_cache.delete(self.class.primary_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
|
||||
def transaction_record_state(state) #:nodoc
|
||||
@_start_transaction_state[state] if defined?(@_start_transaction_state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
240
activerecord/test/cases/transaction_callbacks_test.rb
Normal file
240
activerecord/test/cases/transaction_callbacks_test.rb
Normal file
@ -0,0 +1,240 @@
|
||||
require "cases/helper"
|
||||
require 'models/topic'
|
||||
require 'models/reply'
|
||||
|
||||
class TransactionCallbacksTest < ActiveRecord::TestCase
|
||||
self.use_transactional_fixtures = false
|
||||
fixtures :topics
|
||||
|
||||
class TopicWithCallbacks < ActiveRecord::Base
|
||||
set_table_name :topics
|
||||
|
||||
after_commit{|record| record.send(:do_after_commit, nil)}
|
||||
after_commit(:on => :create){|record| record.send(:do_after_commit, :create)}
|
||||
after_commit(:on => :update){|record| record.send(:do_after_commit, :update)}
|
||||
after_commit(:on => :destroy){|record| record.send(:do_after_commit, :destroy)}
|
||||
after_rollback{|record| record.send(:do_after_rollback, nil)}
|
||||
after_rollback(:on => :create){|record| record.send(:do_after_rollback, :create)}
|
||||
after_rollback(:on => :update){|record| record.send(:do_after_rollback, :update)}
|
||||
after_rollback(:on => :destroy){|record| record.send(:do_after_rollback, :destroy)}
|
||||
|
||||
def history
|
||||
@history ||= []
|
||||
end
|
||||
|
||||
def after_commit_block(on = nil, &block)
|
||||
@after_commit ||= {}
|
||||
@after_commit[on] ||= []
|
||||
@after_commit[on] << block
|
||||
end
|
||||
|
||||
def after_rollback_block(on = nil, &block)
|
||||
@after_rollback ||= {}
|
||||
@after_rollback[on] ||= []
|
||||
@after_rollback[on] << block
|
||||
end
|
||||
|
||||
def do_after_commit(on)
|
||||
blocks = @after_commit[on] if defined?(@after_commit)
|
||||
blocks.each{|b| b.call(self)} if blocks
|
||||
end
|
||||
|
||||
def do_after_rollback(on)
|
||||
blocks = @after_rollback[on] if defined?(@after_rollback)
|
||||
blocks.each{|b| b.call(self)} if blocks
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@first, @second = TopicWithCallbacks.find(1, 3).sort_by { |t| t.id }
|
||||
end
|
||||
|
||||
def test_call_after_commit_after_transaction_commits
|
||||
@first.after_commit_block{|r| r.history << :after_commit}
|
||||
@first.after_rollback_block{|r| r.history << :after_rollback}
|
||||
|
||||
@first.save!
|
||||
assert_equal [:after_commit], @first.history
|
||||
end
|
||||
|
||||
def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record
|
||||
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
|
||||
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
|
||||
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
|
||||
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
|
||||
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
|
||||
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
|
||||
|
||||
@first.save!
|
||||
assert_equal [:commit_on_update], @first.history
|
||||
end
|
||||
|
||||
def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record
|
||||
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
|
||||
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
|
||||
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
|
||||
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
|
||||
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
|
||||
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
|
||||
|
||||
@first.destroy
|
||||
assert_equal [:commit_on_destroy], @first.history
|
||||
end
|
||||
|
||||
def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record
|
||||
@new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today)
|
||||
@new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
|
||||
@new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
|
||||
@new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
|
||||
@new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
|
||||
@new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
|
||||
@new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
|
||||
|
||||
@new_record.save!
|
||||
assert_equal [:commit_on_create], @new_record.history
|
||||
end
|
||||
|
||||
def test_call_after_rollback_after_transaction_rollsback
|
||||
@first.after_commit_block{|r| r.history << :after_commit}
|
||||
@first.after_rollback_block{|r| r.history << :after_rollback}
|
||||
|
||||
Topic.transaction do
|
||||
@first.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
assert_equal [:after_rollback], @first.history
|
||||
end
|
||||
|
||||
def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record
|
||||
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
|
||||
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
|
||||
@first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
|
||||
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
|
||||
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
|
||||
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
|
||||
|
||||
Topic.transaction do
|
||||
@first.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
assert_equal [:rollback_on_update], @first.history
|
||||
end
|
||||
|
||||
def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record
|
||||
@first.after_commit_block(:create){|r| r.history << :commit_on_create}
|
||||
@first.after_commit_block(:update){|r| r.history << :commit_on_update}
|
||||
@first.after_commit_block(:destroy){|r| r.history << :commit_on_update}
|
||||
@first.after_rollback_block(:create){|r| r.history << :rollback_on_create}
|
||||
@first.after_rollback_block(:update){|r| r.history << :rollback_on_update}
|
||||
@first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
|
||||
|
||||
Topic.transaction do
|
||||
@first.destroy
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
assert_equal [:rollback_on_destroy], @first.history
|
||||
end
|
||||
|
||||
def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record
|
||||
@new_record = TopicWithCallbacks.new(:title => "New topic", :written_on => Date.today)
|
||||
@new_record.after_commit_block(:create){|r| r.history << :commit_on_create}
|
||||
@new_record.after_commit_block(:update){|r| r.history << :commit_on_update}
|
||||
@new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy}
|
||||
@new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create}
|
||||
@new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update}
|
||||
@new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy}
|
||||
|
||||
Topic.transaction do
|
||||
@new_record.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
assert_equal [:rollback_on_create], @new_record.history
|
||||
end
|
||||
|
||||
def test_call_after_rollback_when_commit_fails
|
||||
@first.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction)
|
||||
begin
|
||||
@first.connection.class.class_eval do
|
||||
def commit_db_transaction; raise "boom!"; end
|
||||
end
|
||||
|
||||
@first.after_commit_block{|r| r.history << :after_commit}
|
||||
@first.after_rollback_block{|r| r.history << :after_rollback}
|
||||
|
||||
assert !@first.save rescue nil
|
||||
assert_equal [:after_rollback], @first.history
|
||||
ensure
|
||||
@first.connection.class.send(:remove_method, :commit_db_transaction)
|
||||
@first.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction)
|
||||
end
|
||||
end
|
||||
|
||||
def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint
|
||||
def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
|
||||
def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
|
||||
@first.after_rollback_block{|r| r.rollbacks(1)}
|
||||
@first.after_commit_block{|r| r.commits(1)}
|
||||
|
||||
def @second.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
|
||||
def @second.commits(i=0); @commits ||= 0; @commits += i if i; end
|
||||
@second.after_rollback_block{|r| r.rollbacks(1)}
|
||||
@second.after_commit_block{|r| r.commits(1)}
|
||||
|
||||
Topic.transaction do
|
||||
@first.save!
|
||||
Topic.transaction(:requires_new => true) do
|
||||
@second.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal 1, @first.commits
|
||||
assert_equal 0, @first.rollbacks
|
||||
assert_equal 0, @second.commits
|
||||
assert_equal 1, @second.rollbacks
|
||||
end
|
||||
|
||||
def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails
|
||||
def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end
|
||||
def @first.commits(i=0); @commits ||= 0; @commits += i if i; end
|
||||
|
||||
@first.after_rollback_block{|r| r.rollbacks(1)}
|
||||
@first.after_commit_block{|r| r.commits(1)}
|
||||
|
||||
Topic.transaction do
|
||||
@first.save
|
||||
Topic.transaction(:requires_new => true) do
|
||||
@first.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
Topic.transaction(:requires_new => true) do
|
||||
@first.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal 1, @first.commits
|
||||
assert_equal 2, @first.rollbacks
|
||||
end
|
||||
|
||||
def test_after_transaction_callbacks_should_not_raise_errors
|
||||
def @first.last_after_transaction_error=(e); @last_transaction_error = e; end
|
||||
def @first.last_after_transaction_error; @last_transaction_error; end
|
||||
@first.after_commit_block{|r| r.last_after_transaction_error = :commit; raise "fail!";}
|
||||
@first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";}
|
||||
|
||||
@first.save!
|
||||
assert_equal :commit, @first.last_after_transaction_error
|
||||
|
||||
Topic.transaction do
|
||||
@first.save!
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
assert_equal :rollback, @first.last_after_transaction_error
|
||||
end
|
||||
end
|
@ -320,6 +320,33 @@ def test_rollback_when_commit_raises
|
||||
end
|
||||
end
|
||||
|
||||
def test_restore_active_record_state_for_all_records_in_a_transaction
|
||||
topic_1 = Topic.new(:title => 'test_1')
|
||||
topic_2 = Topic.new(:title => 'test_2')
|
||||
Topic.transaction do
|
||||
assert topic_1.save
|
||||
assert topic_2.save
|
||||
@first.save
|
||||
@second.destroy
|
||||
assert_equal false, topic_1.new_record?
|
||||
assert_not_nil topic_1.id
|
||||
assert_equal false, topic_2.new_record?
|
||||
assert_not_nil topic_2.id
|
||||
assert_equal false, @first.new_record?
|
||||
assert_not_nil @first.id
|
||||
assert_equal true, @second.destroyed?
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
assert_equal true, topic_1.new_record?
|
||||
assert_nil topic_1.id
|
||||
assert_equal true, topic_2.new_record?
|
||||
assert_nil topic_2.id
|
||||
assert_equal false, @first.new_record?
|
||||
assert_not_nil @first.id
|
||||
assert_equal false, @second.destroyed?
|
||||
end
|
||||
|
||||
if current_adapter?(:PostgreSQLAdapter) && defined?(PGconn::PQTRANS_IDLE)
|
||||
def test_outside_transaction_works
|
||||
assert Topic.connection.outside_transaction?
|
||||
@ -382,6 +409,12 @@ def test_sqlite_add_column_in_transaction
|
||||
end
|
||||
|
||||
private
|
||||
def define_callback_method(callback_method)
|
||||
define_method(callback_method) do
|
||||
self.history << [callback_method, :method]
|
||||
end
|
||||
end
|
||||
|
||||
def add_exception_raising_after_save_callback_to_topic
|
||||
Topic.class_eval <<-eoruby, __FILE__, __LINE__ + 1
|
||||
remove_method(:after_save_for_transaction)
|
||||
|
Loading…
Reference in New Issue
Block a user