diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index 1d59b7ffa856c..6df57bcf62695 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -40,7 +40,7 @@ def self.add_counter_cache_callbacks(model, reflection) klass._counter_cache_columns << cache_column if klass && klass.respond_to?(:_counter_cache_columns) end - def self.touch_record(o, changes, foreign_key, name, touch) # :nodoc: + def self.touch_record(o, changes, foreign_key, name, touch, touch_method) # :nodoc: old_foreign_id = changes[foreign_key] && changes[foreign_key].first if old_foreign_id @@ -58,9 +58,9 @@ def self.touch_record(o, changes, foreign_key, name, touch) # :nodoc: if old_record if touch != true - old_record.touch_later(touch) + old_record.public_send(touch_method, touch) else - old_record.touch_later + old_record.public_send(touch_method) end end end @@ -68,9 +68,9 @@ def self.touch_record(o, changes, foreign_key, name, touch) # :nodoc: record = o.public_send name if record && record.persisted? if touch != true - record.touch_later(touch) + record.public_send(touch_method, touch) else - record.touch_later + record.public_send(touch_method) end end end @@ -81,7 +81,7 @@ def self.add_touch_callbacks(model, reflection) touch = reflection.options[:touch] callback = lambda { |changes_method| lambda { |record| - BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch) + BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch, belongs_to_touch_method) }} if reflection.counter_cache_column diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index b3288d4ca86e9..8465d4c764993 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -154,11 +154,11 @@ def restore! def rollback_records return unless records - ite = unique_records - + ite = records.uniq(&:__id__) 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| + while record = ite.shift + should_run_callbacks = record.__id__ == instances_to_run_callbacks_on[record].__id__ record.rolledback!(force_restore_state: full_rollback?, should_run_callbacks: should_run_callbacks) end ensure @@ -168,30 +168,19 @@ def rollback_records end def before_commit_records - return unless records - - if @run_commit_callbacks - ite = unique_records - - instances_to_run_callbacks_on = ite.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 - end + records.uniq.each(&:before_committed!) if records && @run_commit_callbacks end def commit_records return unless records - ite = unique_records + ite = records.uniq(&:__id__) 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| + while record = ite.shift + should_run_callbacks = record.__id__ == instances_to_run_callbacks_on[record].__id__ record.committed!(should_run_callbacks: should_run_callbacks) end else @@ -210,18 +199,6 @@ def closed?; false; end def open?; !closed?; end private - def unique_records - records.uniq(&:__id__) - end - - 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 - def prepare_instances_to_run_callbacks_on(records) records.each_with_object({}) do |record, candidates| next unless record.trigger_transactional_callbacks? diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 0c4ff70dd62b2..739a09c3f3752 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -1240,5 +1240,11 @@ def _raise_record_not_touched_error persisted?, new_record?, or destroyed? before touching. MSG end + + # The name of the method used to touch a +belongs_to+ association when the + # +:touch+ option is used. + def belongs_to_touch_method + :touch + end end end diff --git a/activerecord/lib/active_record/touch_later.rb b/activerecord/lib/active_record/touch_later.rb index 50c4679c4772a..0def355d3ac0f 100644 --- a/activerecord/lib/active_record/touch_later.rb +++ b/activerecord/lib/active_record/touch_later.rb @@ -27,7 +27,7 @@ def touch_later(*names) # :nodoc: self.class.reflect_on_all_associations.each do |r| if touch = r.options[:touch] if r.macro == :belongs_to - ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, changes_to_save, r.foreign_key, r.name, touch) + ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, changes_to_save, r.foreign_key, r.name, touch, :touch_later) elsif r.macro == :has_one ActiveRecord::Associations::Builder::HasOne.touch_record(self, r.name, touch) end @@ -61,5 +61,9 @@ def touch_deferred_attributes def has_defer_touch_attrs? defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present? end + + def belongs_to_touch_method + :touch_later + end end end diff --git a/activerecord/test/cases/touch_later_test.rb b/activerecord/test/cases/touch_later_test.rb index 6346bf2cacded..f1a9cf2d05741 100644 --- a/activerecord/test/cases/touch_later_test.rb +++ b/activerecord/test/cases/touch_later_test.rb @@ -6,11 +6,9 @@ require "models/topic" require "models/node" require "models/tree" -require "models/owner" -require "models/pet" class TouchLaterTest < ActiveRecord::TestCase - fixtures :nodes, :trees, :owners, :pets + fixtures :nodes, :trees def test_touch_later_raise_if_non_persisted invoice = Invoice.new @@ -122,18 +120,4 @@ def test_touching_three_deep assert_not_equal nodes(:grandparent).reload.updated_at, previous_grandparent_updated_at assert_not_equal trees(:root).reload.updated_at, previous_tree_updated_at end - - def test_touching_through_nested_attributes - time = Time.now.utc - 25.days - - owner = owners(:blackbeard) - - owner.touch(time: time) - - assert_equal time.to_i, owner.reload.updated_at.to_i - - owner.update pets_attributes: { "0" => { id: "1", name: "Alfred" } } - - assert_not_equal time.to_i, owner.reload.updated_at.to_i - end end