Merge pull request #52305 from joshuay03/fix-52304

[Fix #52304] Avoid computing `klass` if reflection is a `belongs_to` in `ActiveRecord::AutosaveAssociation#inverse_belongs_to_association_for`
This commit is contained in:
Jean Boussier 2024-07-11 10:49:36 +02:00 committed by GitHub
commit e98f4d8496
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 77 additions and 3 deletions

@ -467,6 +467,7 @@ def save_has_one_association(reflection)
end
def inverse_belongs_to_association_for(reflection, record)
!reflection.belongs_to? &&
reflection.inverse_of &&
reflection.inverse_of.belongs_to? &&
record.association(reflection.inverse_of.name)

@ -305,7 +305,7 @@ def test_callbacks_firing_order_on_save
end
def test_callbacks_on_child_when_parent_autosaves_child
eye = Eye.create(iris: Iris.new)
eye = Eye.create!(iris: Iris.new)
assert_equal 1, eye.iris.before_validation_callbacks_counter
assert_equal 1, eye.iris.before_create_callbacks_counter
assert_equal 1, eye.iris.before_save_callbacks_counter
@ -314,8 +314,18 @@ def test_callbacks_on_child_when_parent_autosaves_child
assert_equal 1, eye.iris.after_save_callbacks_counter
end
def test_callbacks_on_child_when_parent_autosaves_polymorphic_child_with_inverse_of
drink_designer = DrinkDesigner.create!(chef: ChefWithPolymorphicInverseOf.new)
assert_equal 1, drink_designer.chef.before_validation_callbacks_counter
assert_equal 1, drink_designer.chef.before_create_callbacks_counter
assert_equal 1, drink_designer.chef.before_save_callbacks_counter
assert_equal 1, drink_designer.chef.after_validation_callbacks_counter
assert_equal 1, drink_designer.chef.after_create_callbacks_counter
assert_equal 1, drink_designer.chef.after_save_callbacks_counter
end
def test_callbacks_on_child_when_child_autosaves_parent
iris = Iris.create(eye: Eye.new)
iris = Iris.create!(eye: Eye.new)
assert_equal 1, iris.before_validation_callbacks_counter
assert_equal 1, iris.before_create_callbacks_counter
assert_equal 1, iris.before_save_callbacks_counter
@ -324,6 +334,16 @@ def test_callbacks_on_child_when_child_autosaves_parent
assert_equal 1, iris.after_save_callbacks_counter
end
def test_callbacks_on_child_when_polymorphic_child_with_inverse_of_autosaves_parent
chef = ChefWithPolymorphicInverseOf.create!(employable: DrinkDesigner.new)
assert_equal 1, chef.before_validation_callbacks_counter
assert_equal 1, chef.before_create_callbacks_counter
assert_equal 1, chef.before_save_callbacks_counter
assert_equal 1, chef.after_validation_callbacks_counter
assert_equal 1, chef.after_create_callbacks_counter
assert_equal 1, chef.after_save_callbacks_counter
end
def test_foreign_key_attribute_is_not_set_unless_changed
eye = Eye.create!(iris_with_read_only_foreign_key_attributes: { color: "honey" })
assert_nothing_raised do

@ -8,3 +8,55 @@ class Chef < ActiveRecord::Base
class ChefList < Chef
belongs_to :employable_list, polymorphic: true
end
class ChefWithPolymorphicInverseOf < Chef
attr_reader :before_validation_callbacks_counter
attr_reader :before_create_callbacks_counter
attr_reader :before_save_callbacks_counter
attr_reader :after_validation_callbacks_counter
attr_reader :after_create_callbacks_counter
attr_reader :after_save_callbacks_counter
belongs_to :employable, polymorphic: true, inverse_of: :chef
accepts_nested_attributes_for :employable
before_validation :update_before_validation_counter
before_create :update_before_create_counter
before_save :update_before_save_counter
after_validation :update_after_validation_counter
after_create :update_after_create_counter
after_save :update_after_save_counter
private
def update_before_validation_counter
@before_validation_callbacks_counter ||= 0
@before_validation_callbacks_counter += 1
end
def update_before_create_counter
@before_create_callbacks_counter ||= 0
@before_create_callbacks_counter += 1
end
def update_before_save_counter
@before_save_callbacks_counter ||= 0
@before_save_callbacks_counter += 1
end
def update_after_validation_counter
@after_validation_callbacks_counter ||= 0
@after_validation_callbacks_counter += 1
end
def update_after_create_counter
@after_create_callbacks_counter ||= 0
@after_create_callbacks_counter += 1
end
def update_after_save_counter
@after_save_callbacks_counter ||= 0
@after_save_callbacks_counter += 1
end
end

@ -2,6 +2,7 @@
class DrinkDesigner < ActiveRecord::Base
has_one :chef, as: :employable
accepts_nested_attributes_for :chef
end
class DrinkDesignerWithPolymorphicDependentNullifyChef < ActiveRecord::Base