From d98763a602ecffa1d375fa974d7c5de8b1145358 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Thu, 21 Feb 2013 14:54:17 +0100 Subject: multiple actions for :on option with `after_commit` and `after_rollback` Closes #988. --- activerecord/CHANGELOG.md | 8 +++++ activerecord/lib/active_record/transactions.rb | 31 ++++++++++--------- .../test/cases/transaction_callbacks_test.rb | 35 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 3410f38063..8e51fdf199 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,13 @@ ## Rails 4.0.0 (unreleased) ## +* The `:on` option for `after_commit` and `after_rollback` now + accepts an Array of actions. + Fixes #988. + + Example: + + after_commit :update_cache on: [:create, :update] + * Rename related indexes on `rename_table` and `rename_column`. This does not affect indexes with custom names. diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 4b7a388dc7..33718ef0e9 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -218,9 +218,8 @@ module ActiveRecord # after_commit :do_bar, on: :update # after_commit :do_baz, on: :destroy # - # Also, to have the callback fired on create and update, but not on destroy: - # - # after_commit :do_zoo, if: :persisted? + # after_commit :do_foo_bar, :on [:create, :update] + # after_commit :do_bar_baz, :on [:update, :destroy] # # Note that transactional fixtures do not play well with this feature. Please # use the +test_after_commit+ gem to have these hooks fired in tests. @@ -244,12 +243,14 @@ module ActiveRecord if options.is_a?(Hash) && options[:on] assert_valid_transaction_action(options[:on]) options[:if] = Array(options[:if]) - options[:if] << "transaction_include_action?(:#{options[:on]})" + fire_on = Array(options[:on]).map(&:to_sym) + options[:if] << "transaction_include_any_action?(#{fire_on})" end end - def assert_valid_transaction_action(action) - unless ACTIONS.include?(action.to_sym) + def assert_valid_transaction_action(actions) + actions = Array(actions) + if (actions - ACTIONS).any? raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS.join(",")}" end end @@ -378,14 +379,16 @@ module ActiveRecord end # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks. - def transaction_include_action?(action) #:nodoc: - case action - when :create - transaction_record_state(:new_record) - when :destroy - destroyed? - when :update - !(transaction_record_state(:new_record) || destroyed?) + def transaction_include_any_action?(actions) #:nodoc: + actions.any? do |action| + case action + when :create + transaction_record_state(:new_record) + when :destroy + destroyed? + when :update + !(transaction_record_state(:new_record) || destroyed?) + end end end end diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index fd5651b4e0..eb4ffd4498 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -312,3 +312,38 @@ class SaveFromAfterCommitBlockTest < ActiveRecord::TestCase assert_equal true, topic.record_updated end end + +class CallbacksOnMultipleActionsTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + class TopicWithCallbacksOnMultipleActions < ActiveRecord::Base + self.table_name = :topics + + after_commit(on: [:create, :destroy]) { |record| record.history << :create_and_destroy } + after_commit(on: [:create, :update]) { |record| record.history << :create_and_update } + after_commit(on: [:update, :destroy]) { |record| record.history << :update_and_destroy } + + def clear_history + @history = [] + end + + def history + @history ||= [] + end + end + + def test_after_commit_on_multiple_actions + topic = TopicWithCallbacksOnMultipleActions.new + topic.save + assert_equal [:create_and_update, :create_and_destroy], topic.history + + topic.clear_history + topic.approved = true + topic.save + assert_equal [:update_and_destroy, :create_and_update], topic.history + + topic.clear_history + topic.destroy + assert_equal [:update_and_destroy, :create_and_destroy], topic.history + end +end -- cgit v1.2.3