Skip to content

Commit 6749767

Browse files
committed
Do not validate associated records that haven't changed
Fix: rails#17621 Redo of: rails#18612 You should be able to create a reference to an invalid record as long as you don't modify it. This was initially fixed in rails#18612 but was reverted in rails@2c02bc0 because it was causing other bugs. Some tests were added as part of the revert to avoid future regressions.
1 parent 9424179 commit 6749767

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

activerecord/lib/active_record/autosave_association.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,14 @@ def validate_collection_association(reflection)
370370
# enabled records if they're marked_for_destruction? or destroyed.
371371
def association_valid?(association, record)
372372
return true if record.destroyed? || (association.options[:autosave] && record.marked_for_destruction?)
373-
374-
context = validation_context if custom_validation_context?
373+
if custom_validation_context?
374+
context = validation_context
375+
else
376+
# If the associated record is unchanged we shouldn't auto validate it.
377+
# Even if a record is invalid you should still be able to create new references
378+
# to it.
379+
return true if !record.new_record? && !record.changed?
380+
end
375381

376382
unless valid = record.valid?(context)
377383
if association.options[:autosave]

activerecord/test/cases/autosave_association_test.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,17 @@ def test_should_skip_validation_on_habtm_if_destroyed
14901490
assert_predicate @pirate, :valid?
14911491
end
14921492

1493+
def test_should_skip_validation_on_habtm_if_persisted_and_unchanged
1494+
parrot = @pirate.parrots.create!(name: "parrots_1")
1495+
parrot.update_column(:name, "")
1496+
parrot.reload
1497+
assert_not_predicate parrot, :valid?
1498+
1499+
new_pirate = Pirate.new(catchphrase: "Arr")
1500+
new_pirate.parrots = @pirate.parrots
1501+
new_pirate.save!
1502+
end
1503+
14931504
def test_a_child_marked_for_destruction_should_not_be_destroyed_twice_while_saving_habtm
14941505
@pirate.parrots.create!(name: "parrots_1")
14951506

0 commit comments

Comments
 (0)