diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index e439848780..eddec18f94 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,12 @@ +* Clear cached `has_one` association after setting `belongs_to` association to `nil`. + + After setting a `belongs_to` relation to `nil` and updating an unrelated attribute on the owner, + the owner should still return `nil` on the `has_one` relation. + + Fixes #42597. + + *Michiel de Mare* + * OpenSSL constants are now used for Digest computations. *Dirkjan Bussink* diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 589057e77c..6aca13fec2 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -77,6 +77,8 @@ def replace(record) raise_on_type_mismatch!(record) set_inverse_instance(record) @updated = true + elsif target + remove_inverse_instance(target) end replace_keys(record, force: true) diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 2d7afd897a..b94e93a124 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -1205,6 +1205,19 @@ def test_reassigning_the_parent_id_updates_the_object assert_equal companies(:another_firm), client.firm_with_condition end + def test_clearing_an_association_clears_the_associations_inverse + author = Author.create(name: "Jimmy Tolkien") + post = author.create_post(title: "The silly medallion", body: "") + assert_equal post, author.post + assert_equal author, post.author + + author.update!(post: nil) + assert_nil author.post + + post.update!(title: "The Silmarillion") + assert_nil author.post + end + def test_destroying_child_with_unloaded_parent_and_foreign_key_and_touch_is_possible_with_has_many_inversing with_has_many_inversing do book = Book.create! diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 8442dc1154..b7f211c24f 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -307,6 +307,19 @@ def test_create_association assert_equal account, firm.reload.account end + def test_clearing_an_association_clears_the_associations_inverse + author = Author.create(name: "Jimmy Tolkien") + post = author.create_post(title: "The silly medallion", body: "") + assert_equal post, author.post + assert_equal author, post.author + + post.update!(author: nil) + assert_nil post.author + + author.update!(name: "J.R.R. Tolkien") + assert_nil post.author + end + def test_create_association_with_bang firm = Firm.create(name: "GlobalMegaCorp") account = firm.create_account!(credit_limit: 1000)