From c7f669af6f1d8e9053a586c97584702971e1906c Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 20 Jun 2017 17:35:13 -0700 Subject: Clear offset cache on CollectionProxy reset/reload The `@offsets` cache is used by FinderMethods to cache records found by find_nth. This cache is cleared in AR::Relation#reset, but not in CollectionProxy#reset or CollectionProxy#reload. Because of this, since #29098, calling #first/#find_nth/etc after calling #reload or #reset on an association could return a stale record. This is an issue both when the full association target is loaded and when the item is loaded in #find_nth. This commit solves the problem by clearing the `@offsets` cache in CollectionProxy#reset and CollectionProxy#reload. --- .../associations/has_many_associations_test.rb | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'activerecord/test/cases') diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 590d3642bd..ae58dbff21 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -741,6 +741,32 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal client2, firm.clients.merge!(where: ["#{QUOTED_TYPE} = :type", { type: "Client" }], order: "id").first end + def test_find_first_after_reset + firm = Firm.all.merge!(order: "id").first + + # Calling first twice should return the same object + original_object_id = firm.clients.first.object_id + assert_equal firm.clients.first.object_id, original_object_id, "Expected multiple invocations of #first to return the same object" + + firm.clients.reset + + # It should return a different object, since the association has been reloaded + assert_not_equal original_object_id, firm.clients.first.object_id, "Expected #first after #reload to return a new object" + end + + def test_find_first_after_reload + firm = Firm.all.merge!(order: "id").first + + # Calling first twice should return the same object + original_object_id = firm.clients.first.object_id + assert_equal firm.clients.first.object_id, original_object_id, "Expected multiple invocations of #first to return the same object" + + firm.clients.reload + + # It should return a different object, since the association has been reloaded + assert_not_equal original_object_id, firm.clients.first.object_id, "Expected #first after #reload to return a new object" + end + def test_find_all_with_include_and_conditions assert_nothing_raised do Developer.all.merge!(joins: :audit_logs, where: { "audit_logs.message" => nil, :name => "Smith" }).to_a -- cgit v1.2.3