aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG.md18
-rw-r--r--activerecord/lib/active_record/transactions.rb26
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb6
-rw-r--r--guides/source/active_record_callbacks.md19
4 files changed, 63 insertions, 6 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index fdc95f718a..56a3232ee9 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,21 @@
+* Introduce after_{create,update,delete}_commit callbacks.
+
+ Before:
+
+ after_commit :add_to_index_later, on: :create
+ after_commit :update_in_index_later, on: :update
+ after_commit :remove_from_index_later, on: :destroy
+
+ After:
+
+ after_create_commit :add_to_index_later
+ after_update_commit :update_in_index_later
+ after_destroy_commit :remove_from_index_later
+
+ Fixes #22515.
+
+ *Genadi Samokovarov*
+
* Respect the column default values for `inheritance_column` when
instantiating records through the base class.
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 8de82feae3..38ab1f3fc6 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -233,6 +233,24 @@ module ActiveRecord
set_callback(:commit, :after, *args, &block)
end
+ # Shortcut for +after_commit :hook, on: :create+.
+ def after_create_commit(*args, &block)
+ set_options_for_callbacks!(args, on: :create)
+ set_callback(:commit, :after, *args, &block)
+ end
+
+ # Shortcut for +after_commit :hook, on: :update+.
+ def after_update_commit(*args, &block)
+ set_options_for_callbacks!(args, on: :update)
+ set_callback(:commit, :after, *args, &block)
+ end
+
+ # Shortcut for +after_commit :hook, on: :destroy+.
+ def after_destroy_commit(*args, &block)
+ set_options_for_callbacks!(args, on: :destroy)
+ set_callback(:commit, :after, *args, &block)
+ end
+
# This callback is called after a create, update, or destroy are rolled back.
#
# Please check the documentation of #after_commit for options.
@@ -268,9 +286,11 @@ module ActiveRecord
private
- def set_options_for_callbacks!(args)
- options = args.last
- if options.is_a?(Hash) && options[:on]
+ def set_options_for_callbacks!(args, enforced_options = {})
+ options = args.extract_options!.merge!(enforced_options)
+ args << options
+
+ if options[:on]
fire_on = Array(options[:on])
assert_valid_transaction_action(fire_on)
options[:if] = Array(options[:if])
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index f2229939c8..637f89196e 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -35,9 +35,9 @@ class TransactionCallbacksTest < ActiveRecord::TestCase
has_many :replies, class_name: "ReplyWithCallbacks", foreign_key: "parent_id"
after_commit { |record| record.do_after_commit(nil) }
- after_commit(on: :create) { |record| record.do_after_commit(:create) }
- after_commit(on: :update) { |record| record.do_after_commit(:update) }
- after_commit(on: :destroy) { |record| record.do_after_commit(:destroy) }
+ after_create_commit { |record| record.do_after_commit(:create) }
+ after_update_commit { |record| record.do_after_commit(:update) }
+ after_destroy_commit { |record| record.do_after_commit(:destroy) }
after_rollback { |record| record.do_after_rollback(nil) }
after_rollback(on: :create) { |record| record.do_after_rollback(:create) }
after_rollback(on: :update) { |record| record.do_after_rollback(:update) }
diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md
index 13989a3b33..b5ad3e9411 100644
--- a/guides/source/active_record_callbacks.md
+++ b/guides/source/active_record_callbacks.md
@@ -412,4 +412,23 @@ end
NOTE: the `:on` option specifies when a callback will be fired. If you
don't supply the `:on` option the callback will fire for every action.
+Since using `after_commit` callback only on create, update or delete is
+common, there are aliases for those operations:
+
+* `after_create_commit`
+* `after_update_commit`
+* `after_destroy_commit`
+
+```ruby
+class PictureFile < ActiveRecord::Base
+ after_destroy_commit :delete_picture_file_from_disk
+
+ def delete_picture_file_from_disk
+ if File.exist?(filepath)
+ File.delete(filepath)
+ end
+ end
+end
+```
+
WARNING. The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback.