aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases
diff options
context:
space:
mode:
authorStefan Budeanu <stefan.budeanu@shopify.com>2016-12-01 17:39:15 -0500
committerStefan Budeanu <stefan.budeanu@shopify.com>2016-12-09 11:14:37 -0500
commit371c083fb0620efebf7bd0188a66486403e12ecc (patch)
tree4c10587ae04edb22e00e4c0a8d1ba2024786057d /activerecord/test/cases
parent872faa958398fa5aaf6b0e4cd6a8090503d6885a (diff)
downloadrails-371c083fb0620efebf7bd0188a66486403e12ecc.tar.gz
rails-371c083fb0620efebf7bd0188a66486403e12ecc.tar.bz2
rails-371c083fb0620efebf7bd0188a66486403e12ecc.zip
Emulate db trigger behaviour for after_commit :destroy, :update
Race conditions can occur when an ActiveRecord is destroyed twice or destroyed and updated. The callbacks should only be triggered once, similar to a SQL database trigger.
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb45
1 files changed, 45 insertions, 0 deletions
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index dba100f5c9..391bbe8877 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -449,6 +449,51 @@ class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase
end
end
+class CallbacksOnDestroyUpdateActionRaceTest < ActiveRecord::TestCase
+ class TopicWithHistory < ActiveRecord::Base
+ self.table_name = :topics
+
+ def self.clear_history
+ @@history = []
+ end
+
+ def self.history
+ @@history ||= []
+ end
+ end
+
+ class TopicWithCallbacksOnDestroy < TopicWithHistory
+ after_commit(on: :destroy) { |record| record.class.history << :destroy }
+ end
+
+ class TopicWithCallbacksOnUpdate < TopicWithHistory
+ after_commit(on: :update) { |record| record.class.history << :update }
+ end
+
+ def test_trigger_once_on_multiple_deletions
+ TopicWithCallbacksOnDestroy.clear_history
+ topic = TopicWithCallbacksOnDestroy.new
+ topic.save
+ topic_clone = TopicWithCallbacksOnDestroy.find(topic.id)
+ topic.destroy
+ topic_clone.destroy
+
+ assert_equal [:destroy], TopicWithCallbacksOnDestroy.history
+ end
+
+ def test_trigger_on_update_where_row_was_deleted
+ TopicWithCallbacksOnUpdate.clear_history
+ topic = TopicWithCallbacksOnUpdate.new
+ topic.save
+ topic_clone = TopicWithCallbacksOnUpdate.find(topic.id)
+ topic.destroy
+ topic_clone.author_name = "Test Author"
+ topic_clone.save
+
+ assert_equal [], TopicWithCallbacksOnUpdate.history
+ end
+end
+
class TransactionEnrollmentCallbacksTest < ActiveRecord::TestCase
class TopicWithoutTransactionalEnrollmentCallbacks < ActiveRecord::Base
self.table_name = :topics