diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 96bf5dd705df1..398278883cbe9 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -33,7 +33,8 @@ module Associations # owner, the collection of its posts as target, and # the reflection object represents a :has_many macro. class Association # :nodoc: - attr_reader :owner, :target, :reflection, :disable_joins + attr_accessor :owner + attr_reader :target, :reflection, :disable_joins delegate :options, to: :reflection diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 9e9219a46b8cd..689f4ee36138f 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -1078,6 +1078,7 @@ def reload(options = nil) end @association_cache = fresh_object.instance_variable_get(:@association_cache) + @association_cache.each_value { |association| association.owner = self } @attributes = fresh_object.instance_variable_get(:@attributes) @new_record = false @previously_new_record = false diff --git a/activerecord/test/cases/persistence/reload_association_cache_test.rb b/activerecord/test/cases/persistence/reload_association_cache_test.rb new file mode 100644 index 0000000000000..caf9d4fd10dd5 --- /dev/null +++ b/activerecord/test/cases/persistence/reload_association_cache_test.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require "cases/helper" +require "models/publication" +require "models/editorship" +require "models/editor" + +class ReloadAssociationCacheTest < ActiveRecord::TestCase + def test_reload_sets_correct_owner_for_association_cache + publication = Publication.create!(name: "Rails Way") + assert_equal "Rails Way (touched)", publication.name + publication.reload + assert_equal "Rails Way", publication.name + publication.transaction do + publication.editors = [publication.build_editor_in_chief(name: "Alex Black")] + publication.save! + end + assert_equal "Rails Way (touched)", publication.name + end +end diff --git a/activerecord/test/models/editor.rb b/activerecord/test/models/editor.rb new file mode 100644 index 0000000000000..d75f8ebea763b --- /dev/null +++ b/activerecord/test/models/editor.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class Editor < ActiveRecord::Base + self.primary_key = "name" + + has_one :publication, foreign_key: :editor_in_chief_id, inverse_of: :editor_in_chief + has_many :editorships +end diff --git a/activerecord/test/models/editorship.rb b/activerecord/test/models/editorship.rb new file mode 100644 index 0000000000000..2620cf5b97a5a --- /dev/null +++ b/activerecord/test/models/editorship.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class Editorship < ActiveRecord::Base + belongs_to :publication + belongs_to :editor +end diff --git a/activerecord/test/models/publication.rb b/activerecord/test/models/publication.rb new file mode 100644 index 0000000000000..6873709f113c2 --- /dev/null +++ b/activerecord/test/models/publication.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Publication < ActiveRecord::Base + belongs_to :editor_in_chief, class_name: "Editor", inverse_of: :publication, optional: true + has_many :editorships + has_many :editors, through: :editorships + + after_initialize do + self.editor_in_chief = build_editor_in_chief(name: "John Doe") + end + + after_save_commit :touch_name + def touch_name + self.name = "#{name} (touched)" + end +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 7ba19dfcaee96..b5c6263f75d43 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -562,6 +562,15 @@ t.index [:source_id, :sink_id], unique: true, name: "unique_edge_index" end + create_table :editorships, force: true do |t| + t.string :publication_id + t.string :editor_id + end + + create_table :editors, force: true do |t| + t.string :name + end + create_table :engines, force: true do |t| t.references :car, index: false end @@ -1038,6 +1047,11 @@ t.integer :mentor_id end + create_table :publications, force: true do |t| + t.column :name, :string + t.integer :editor_in_chief_id + end + create_table :randomly_named_table1, force: true do |t| t.string :some_attribute t.integer :another_attribute