Fix: Inconsistent Polymorphic Association Autosave
This commit is contained in:
parent
e6d4ac0e50
commit
589321d99a
@ -463,7 +463,8 @@ def save_has_one_association(reflection)
|
||||
# If the record is new or it has changed, returns true.
|
||||
def _record_changed?(reflection, record, key)
|
||||
record.new_record? ||
|
||||
association_foreign_key_changed?(reflection, record, key) ||
|
||||
(association_foreign_key_changed?(reflection, record, key) ||
|
||||
inverse_polymorphic_association_changed?(reflection, record)) ||
|
||||
record.will_save_change_to_attribute?(reflection.foreign_key)
|
||||
end
|
||||
|
||||
@ -473,6 +474,14 @@ def association_foreign_key_changed?(reflection, record, key)
|
||||
record._has_attribute?(reflection.foreign_key) && record._read_attribute(reflection.foreign_key) != key
|
||||
end
|
||||
|
||||
def inverse_polymorphic_association_changed?(reflection, record)
|
||||
return false unless reflection.inverse_of&.polymorphic?
|
||||
|
||||
class_name = record._read_attribute(reflection.inverse_of.foreign_type)
|
||||
|
||||
reflection.active_record != record.class.polymorphic_class_for(class_name)
|
||||
end
|
||||
|
||||
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
||||
#
|
||||
# In addition, it will destroy the association if it was marked for destruction.
|
||||
|
@ -36,6 +36,9 @@
|
||||
require "models/reply"
|
||||
require "models/attachment"
|
||||
require "models/translation"
|
||||
require "models/chef"
|
||||
require "models/cake_designer"
|
||||
require "models/drink_designer"
|
||||
|
||||
class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase
|
||||
def test_autosave_works_even_when_other_callbacks_update_the_parent_model
|
||||
@ -1276,6 +1279,8 @@ def destroy(*args)
|
||||
end
|
||||
|
||||
class TestAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCase
|
||||
fixtures :chefs, :cake_designers, :drink_designers
|
||||
|
||||
self.use_transactional_tests = false unless supports_savepoints?
|
||||
|
||||
def setup
|
||||
@ -1416,6 +1421,34 @@ def test_mark_for_destruction_is_ignored_without_autosave_true
|
||||
|
||||
assert_not_predicate ship, :valid?
|
||||
end
|
||||
|
||||
def test_recognises_inverse_polymorphic_association_changes_with_same_foreign_key
|
||||
chef_a = chefs(:gordon_ramsay)
|
||||
chef_b = chefs(:marco_pierre_white)
|
||||
|
||||
cake_designer_a = cake_designers(:flora) # id: 1
|
||||
cake_designer_a.update!(chef: chef_a)
|
||||
cake_designer_b = cake_designers(:frosty) # id: 3
|
||||
cake_designer_b.update!(chef: chef_b)
|
||||
|
||||
drink_designer_a = drink_designers(:turner) # id: 1
|
||||
drink_designer_b = drink_designers(:sparrow) # id: 2
|
||||
|
||||
swap_chefs(cake_designer_b, drink_designer_b)
|
||||
assert_predicate cake_designer_b.reload.chef, :present?
|
||||
assert_not_predicate drink_designer_b.reload.chef, :present?
|
||||
|
||||
swap_chefs(cake_designer_a, drink_designer_a)
|
||||
assert_predicate cake_designer_a.reload.chef, :present?
|
||||
assert_not_predicate drink_designer_a.reload.chef, :present?
|
||||
end
|
||||
|
||||
private
|
||||
def swap_chefs(cake_designer, drink_designer)
|
||||
drink_designer.chef = cake_designer.chef
|
||||
drink_designer.save!
|
||||
cake_designer.save!
|
||||
end
|
||||
end
|
||||
|
||||
class TestAutosaveAssociationOnAHasOneThroughAssociation < ActiveRecord::TestCase
|
||||
|
5
activerecord/test/fixtures/cake_designers.yml
vendored
Normal file
5
activerecord/test/fixtures/cake_designers.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
flora:
|
||||
id: 1
|
||||
|
||||
frosty:
|
||||
id: 2
|
5
activerecord/test/fixtures/chefs.yml
vendored
Normal file
5
activerecord/test/fixtures/chefs.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
gordon_ramsay:
|
||||
id: 1
|
||||
|
||||
marco_pierre_white:
|
||||
id: 2
|
5
activerecord/test/fixtures/drink_designers.yml
vendored
Normal file
5
activerecord/test/fixtures/drink_designers.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
turner:
|
||||
id: 1
|
||||
|
||||
sparrow:
|
||||
id: 3
|
Loading…
Reference in New Issue
Block a user