Skip to content

Commit b0fc04a

Browse files
committed
Merge pull request #32119 from fegorodscy/master
Fix dependence on has_one/belongs_to relationships (cherry picked from commit 13e35a5)
1 parent 73c1627 commit b0fc04a

File tree

5 files changed

+65
-1
lines changed

5 files changed

+65
-1
lines changed

‎activerecord/CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
* Fix `dependent: :destroy` issue for has_one/belongs_to relationship where
2+
the parent class was getting deleted when the child was not.
3+
4+
Fixes #32022.
5+
6+
*Fernando Gorodscy*
7+
18
* Whitelist `NULLS FIRST` and `NULLS LAST` in order clauses too.
29

310
*Xavier Noria*

‎activerecord/lib/active_record/associations/belongs_to_association.rb‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ module Associations
55
# = Active Record Belongs To Association
66
class BelongsToAssociation < SingularAssociation #:nodoc:
77
def handle_dependency
8-
target.send(options[:dependent]) if load_target
8+
return unless load_target
9+
10+
case options[:dependent]
11+
when :destroy
12+
target.destroy
13+
raise ActiveRecord::Rollback unless target.destroyed?
14+
else
15+
target.send(options[:dependent])
16+
end
917
end
1018

1119
def replace(record)

‎activerecord/lib/active_record/associations/has_one_association.rb‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def delete(method = options[:dependent])
6060
when :destroy
6161
target.destroyed_by_association = reflection
6262
target.destroy
63+
throw(:abort) unless target.destroyed?
6364
when :nullify
6465
target.update_columns(reflection.foreign_key => nil) if target.persisted?
6566
end

‎activerecord/test/cases/associations/belongs_to_associations_test.rb‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,30 @@ def test_belongs_to_invalid_dependent_option_raises_exception
931931
assert_equal error.message, "The :dependent option must be one of [:destroy, :delete], but is :nullify"
932932
end
933933

934+
class DestroyableBook < ActiveRecord::Base
935+
self.table_name = "books"
936+
belongs_to :author, class_name: "UndestroyableAuthor", dependent: :destroy
937+
end
938+
939+
class UndestroyableAuthor < ActiveRecord::Base
940+
self.table_name = "authors"
941+
has_one :book, class_name: "DestroyableBook", foreign_key: "author_id"
942+
before_destroy :dont
943+
944+
def dont
945+
throw(:abort)
946+
end
947+
end
948+
949+
def test_dependency_should_halt_parent_destruction
950+
author = UndestroyableAuthor.create!(name: "Test")
951+
book = DestroyableBook.create!(author: author)
952+
953+
assert_no_difference ["UndestroyableAuthor.count", "DestroyableBook.count"] do
954+
assert_not book.destroy
955+
end
956+
end
957+
934958
def test_attributes_are_being_set_when_initialized_from_belongs_to_association_with_where_clause
935959
new_firm = accounts(:signals37).build_firm(name: "Apple")
936960
assert_equal new_firm.name, "Apple"

‎activerecord/test/cases/associations/has_one_associations_test.rb‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,4 +725,28 @@ class DestroyByParentAuthor < ActiveRecord::Base
725725

726726
assert_not DestroyByParentBook.exists?(book.id)
727727
end
728+
729+
class UndestroyableBook < ActiveRecord::Base
730+
self.table_name = "books"
731+
belongs_to :author, class_name: "DestroyableAuthor"
732+
before_destroy :dont
733+
734+
def dont
735+
throw(:abort)
736+
end
737+
end
738+
739+
class DestroyableAuthor < ActiveRecord::Base
740+
self.table_name = "authors"
741+
has_one :book, class_name: "UndestroyableBook", foreign_key: "author_id", dependent: :destroy
742+
end
743+
744+
def test_dependency_should_halt_parent_destruction
745+
author = DestroyableAuthor.create!(name: "Test")
746+
UndestroyableBook.create!(author: author)
747+
748+
assert_no_difference ["DestroyableAuthor.count", "UndestroyableBook.count"] do
749+
assert_not author.destroy
750+
end
751+
end
728752
end

0 commit comments

Comments
 (0)