Skip to content

Commit 6be41ad

Browse files
authored
Merge pull request rails#48416 from Shopify/fix-has-one-deletion
Add tests around has_one changing the target and validators
2 parents 55c3066 + ec1aa50 commit 6be41ad

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

activerecord/lib/active_record/associations/has_one_association.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ def set_new_record(record)
9292
replace(record, false)
9393
end
9494

95+
def replace_keys(record, force: false)
96+
# Has one association doesn't have foreign keys to replace.
97+
end
98+
9599
def remove_target!(method)
96100
case method
97101
when :delete

activerecord/lib/active_record/associations/singular_association.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def _create_record(attributes, raise_error = false, &block)
5757
reflection.klass.transaction do
5858
record = build(attributes, &block)
5959
saved = record.save
60-
set_new_record(record)
60+
replace_keys(record, force: true)
6161
raise RecordInvalid.new(record) if !saved && raise_error
6262
record
6363
end

activerecord/test/cases/associations/has_one_associations_test.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
require "models/membership"
2121
require "models/parrot"
2222
require "models/cpk"
23+
require "models/user"
24+
require "models/content"
2325

2426
class HasOneAssociationsTest < ActiveRecord::TestCase
2527
self.use_transactional_tests = false unless supports_savepoints?
@@ -905,6 +907,46 @@ def test_has_one_with_touch_option_on_nonpersisted_built_associations_doesnt_upd
905907
end
906908
end
907909

910+
class InvalidPost < Post
911+
validate :always_fail
912+
913+
def always_fail
914+
errors.add(:base, "Oops")
915+
end
916+
end
917+
918+
test "preserve old record if new one is invalid" do
919+
author = Author.create!(id: 33, name: "Hank Moody")
920+
author.create_post!(id: 1234, title: "Some title", body: "Some content")
921+
922+
assert_no_difference -> { Post.count } do
923+
assert_raises ActiveRecord::RecordNotSaved do
924+
author.post = InvalidPost.new(title: "Some title", body: "Some content")
925+
end
926+
author.save!
927+
end
928+
end
929+
930+
class SpecialContentPosition < ActiveRecord::Base
931+
self.table_name = "content_positions"
932+
belongs_to :content, class_name: name + "::SpecialContentPosition"
933+
validates :content_id, presence: true, uniqueness: true
934+
end
935+
936+
class SpecialContent < ActiveRecord::Base
937+
self.table_name = "content"
938+
has_one :content_position, dependent: :destroy, foreign_key: :content_id, class_name: SpecialContentPosition.name
939+
end
940+
941+
test "uniqueness validator doesn't prevent from replacing the old record if dependent: :destroy is set" do
942+
content = SpecialContent.create!
943+
content.create_content_position!
944+
945+
assert_no_difference -> { ContentPosition.count } do
946+
content.create_content_position!
947+
end
948+
end
949+
908950
test "composite primary key malformed association" do
909951
error = assert_raises(ActiveRecord::CompositePrimaryKeyMismatchError) do
910952
order = Cpk::BrokenOrder.new(id: [1, 2], book: Cpk::Book.new(title: "Some book"))

0 commit comments

Comments
 (0)