diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-27 09:28:27 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-27 09:28:27 +0900 |
commit | ced783fe74ea8683fbc09812ed0e0cadf449a358 (patch) | |
tree | 125398dfc6de4749ab8f53a2ba60430293c6af9a | |
parent | 6349ad300f2cace625b1c733410c4a39c91028ec (diff) | |
download | rails-ced783fe74ea8683fbc09812ed0e0cadf449a358.tar.gz rails-ced783fe74ea8683fbc09812ed0e0cadf449a358.tar.bz2 rails-ced783fe74ea8683fbc09812ed0e0cadf449a358.zip |
Fix inconsistent touching behavior between assigning and unassigning
On belongs_to with `touch: true` association, unassigned object is
caused touching, but assigned object is not touched.
And also, if primary key is customized, it will touch against the wrong
target looked up by the customized key as primary key.
This change ensures correctly touching consistently between assigning
and unassigning.
4 files changed, 29 insertions, 3 deletions
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index cea2570ac4..08f450278d 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -83,7 +83,7 @@ module ActiveRecord def update_counters_on_replace(record) if require_counter_update? && different_target?(record) owner.instance_variable_set :@_after_replace_counter_called, true - record.increment!(reflection.counter_cache_column) + record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch]) decrement_counters end end diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb index 9e012285e5..4b6cb76081 100644 --- a/activerecord/lib/active_record/associations/builder/belongs_to.rb +++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb @@ -92,7 +92,8 @@ module ActiveRecord::Associations::Builder # :nodoc: else klass = association.klass end - old_record = klass.find_by(klass.primary_key => old_foreign_id) + primary_key = reflection.association_primary_key(klass) + old_record = klass.find_by(primary_key => old_foreign_id) if old_record if touch != true diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 6cbde2796a..9ca9ab62a1 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -557,6 +557,31 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal 1, Topic.find(topic.id)[:replies_count] end + def test_belongs_to_touch_with_reassigning + debate = Topic.create!(title: "debate") + debate2 = Topic.create!(title: "debate2") + reply = Reply.create!(title: "blah!", content: "world around!", parent_title: "debate2") + + time = 1.day.ago + + debate.touch(time: time) + debate2.touch(time: time) + + reply.parent_title = "debate" + reply.save! + + assert_operator debate.reload.updated_at, :>, time + assert_operator debate2.reload.updated_at, :>, time + + debate.touch(time: time) + debate2.touch(time: time) + + reply.topic_with_primary_key = debate2 + + assert_operator debate.reload.updated_at, :>, time + assert_operator debate2.reload.updated_at, :>, time + end + def test_belongs_to_with_touch_option_on_touch line_item = LineItem.create! Invoice.create!(line_items: [line_item]) diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index bc829ec67f..d1cee58788 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -4,7 +4,7 @@ require "models/topic" class Reply < Topic belongs_to :topic, foreign_key: "parent_id", counter_cache: true - belongs_to :topic_with_primary_key, class_name: "Topic", primary_key: "title", foreign_key: "parent_title", counter_cache: "replies_count" + belongs_to :topic_with_primary_key, class_name: "Topic", primary_key: "title", foreign_key: "parent_title", counter_cache: "replies_count", touch: true has_many :replies, class_name: "SillyReply", dependent: :destroy, foreign_key: "parent_id" end |