提交 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)
touch = reflection.options[:touch]
callback = lambda { |record|
touch_method = touching_delayed_records? ? :touch : :touch_later
BelongsTo.touch_record(record, foreign_key, n, touch, touch_method)
BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
}
model.after_save callback, if: :changed?
......
......@@ -567,5 +567,9 @@ def _raise_record_not_destroyed
ensure
@_association_destroy_exception = nil
end
def belongs_to_touch_method
:touch
end
end
end
......@@ -16,6 +16,13 @@ def touch_later(*names) # :nodoc:
surreptitiously_touch @_defer_touch_attrs
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
def touch(*names, time: nil) # :nodoc:
......@@ -26,6 +33,7 @@ def touch(*names, time: nil) # :nodoc:
end
private
def surreptitiously_touch(attrs)
attrs.each { |attr| write_attribute attr, @_touch_time }
clear_attribute_changes attrs
......@@ -33,9 +41,8 @@ def surreptitiously_touch(attrs)
def touch_deferred_attributes
if has_defer_touch_attrs? && persisted?
@_touching_delayed_records = true
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
......@@ -43,8 +50,9 @@ def has_defer_touch_attrs?
defined?(@_defer_touch_attrs) && @_defer_touch_attrs.present?
end
def touching_delayed_records?
defined?(@_touching_delayed_records) && @_touching_delayed_records
def belongs_to_touch_method
:touch_later
end
end
end
......@@ -95,8 +95,6 @@ def test_touch_later_dont_hit_the_db
end
def test_touching_three_deep
skip "Pending from #19324"
previous_tree_updated_at = trees(:root).updated_at
previous_grandparent_updated_at = nodes(:grandparent).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.
先完成此消息的编辑!
想要评论请 注册