提交 e7c48db5 编写于 作者: A Arthur Neves

Make sure we touch all the parents when touch_later.

The problem was that when saving an object, we would
call touch_later on the parent which wont be saved immediteally, and
it wont call any callbacks. That was working one level up because
we were calling touch, during the touch_later commit phase. However that still
didnt solve the problem when you have a 3+ levels of parents to be touched,
as calling touch would affect the parent, but it would be too late to run callbacks
on its grand-parent.

The solution for this, is instead, call touch_later upwards when the first
touch_later is called. So we make sure all the timestamps are updated without relying
on callbacks.

This also removed the hard dependency BelongsTo builder had with the TouchLater module.
So we can still have the old behaviour if TouchLater module is not included.

[fixes 5f5e6d92]
[related #19324]
上级 ff891616
...@@ -106,8 +106,7 @@ def self.add_touch_callbacks(model, reflection) ...@@ -106,8 +106,7 @@ def self.add_touch_callbacks(model, reflection)
touch = reflection.options[:touch] touch = reflection.options[:touch]
callback = lambda { |record| callback = lambda { |record|
touch_method = touching_delayed_records? ? :touch : :touch_later BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
BelongsTo.touch_record(record, foreign_key, n, touch, touch_method)
} }
model.after_save callback, if: :changed? model.after_save callback, if: :changed?
......
...@@ -567,5 +567,9 @@ def _raise_record_not_destroyed ...@@ -567,5 +567,9 @@ def _raise_record_not_destroyed
ensure ensure
@_association_destroy_exception = nil @_association_destroy_exception = nil
end end
def belongs_to_touch_method
:touch
end
end end
end end
...@@ -16,6 +16,13 @@ def touch_later(*names) # :nodoc: ...@@ -16,6 +16,13 @@ def touch_later(*names) # :nodoc:
surreptitiously_touch @_defer_touch_attrs surreptitiously_touch @_defer_touch_attrs
self.class.connection.add_transaction_record self self.class.connection.add_transaction_record self
# touch the parents as we are not calling the after_save callbacks
self.class.reflect_on_all_associations(:belongs_to).each do |r|
if touch = r.options[:touch]
ActiveRecord::Associations::Builder::BelongsTo.touch_record(self, r.foreign_key, r.name, touch, :touch_later)
end
end
end end
def touch(*names, time: nil) # :nodoc: def touch(*names, time: nil) # :nodoc:
...@@ -26,6 +33,7 @@ def touch(*names, time: nil) # :nodoc: ...@@ -26,6 +33,7 @@ def touch(*names, time: nil) # :nodoc:
end end
private private
def surreptitiously_touch(attrs) def surreptitiously_touch(attrs)
attrs.each { |attr| write_attribute attr, @_touch_time } attrs.each { |attr| write_attribute attr, @_touch_time }
clear_attribute_changes attrs clear_attribute_changes attrs
...@@ -33,9 +41,8 @@ def surreptitiously_touch(attrs) ...@@ -33,9 +41,8 @@ def surreptitiously_touch(attrs)
def touch_deferred_attributes def touch_deferred_attributes
if has_defer_touch_attrs? && persisted? if has_defer_touch_attrs? && persisted?
@_touching_delayed_records = true
touch(*@_defer_touch_attrs, time: @_touch_time) touch(*@_defer_touch_attrs, time: @_touch_time)
@_touching_delayed_records, @_defer_touch_attrs, @_touch_time = nil, nil, nil @_defer_touch_attrs, @_touch_time = nil, nil
end end
end end
...@@ -43,8 +50,9 @@ def has_defer_touch_attrs? ...@@ -43,8 +50,9 @@ def has_defer_touch_attrs?
defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present? defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present?
end end
def touching_delayed_records? def belongs_to_touch_method
defined?(@_touching_delayed_records) && @_touching_delayed_records :touch_later
end end
end end
end end
...@@ -95,8 +95,6 @@ def test_touch_later_dont_hit_the_db ...@@ -95,8 +95,6 @@ def test_touch_later_dont_hit_the_db
end end
def test_touching_three_deep def test_touching_three_deep
skip "Pending from #19324"
previous_tree_updated_at = trees(:root).updated_at previous_tree_updated_at = trees(:root).updated_at
previous_grandparent_updated_at = nodes(:grandparent).updated_at previous_grandparent_updated_at = nodes(:grandparent).updated_at
previous_parent_updated_at = nodes(:parent_a).updated_at previous_parent_updated_at = nodes(:parent_a).updated_at
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册