mirror of https://github.com/rails/rails
This PR addresses the issue described in #28025. On `dependent: :nullify` strategy only the foreign key of the relation is nullified. However on polymorphic associations the `*_type` column is not nullified leaving the record with a NULL `*_id` but the `*_type` column is present.
This commit is contained in:
parent
e4213e7c68
commit
41ffddbc8b
|
@ -1,3 +1,8 @@
|
|||
* Set polymorphic type column to NULL on `dependent: :nullify` strategy.
|
||||
|
||||
On polymorphic associations both the foreign key and the foreign type columns will be set to NULL.
|
||||
|
||||
*Laerti Papa*
|
||||
|
||||
* Allow `ActionController::Params` as argument of `ActiveRecord::Base#exists?`.
|
||||
|
||||
|
|
|
@ -1293,7 +1293,8 @@ module ActiveRecord
|
|||
#
|
||||
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
||||
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
||||
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
|
||||
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
|
||||
# on polymorphic associations. Callbacks are not executed.
|
||||
# * <tt>:restrict_with_exception</tt> causes an <tt>ActiveRecord::DeleteRestrictionError</tt> exception to be raised if there are any associated records.
|
||||
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
|
||||
#
|
||||
|
@ -1436,7 +1437,8 @@ module ActiveRecord
|
|||
#
|
||||
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
||||
# * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
||||
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
|
||||
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
|
||||
# on polymorphic associations. Callbacks are not executed.
|
||||
# * <tt>:restrict_with_exception</tt> causes an <tt>ActiveRecord::DeleteRestrictionError</tt> exception to be raised if there is an associated record
|
||||
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
|
||||
#
|
||||
|
|
|
@ -9,5 +9,12 @@ module ActiveRecord::Associations
|
|||
false
|
||||
end
|
||||
end
|
||||
|
||||
def nullified_owner_attributes
|
||||
Hash.new.tap do |attrs|
|
||||
attrs[reflection.foreign_key] = nil
|
||||
attrs[reflection.type] = nil if reflection.type.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -92,7 +92,7 @@ module ActiveRecord
|
|||
if method == :delete_all
|
||||
scope.delete_all
|
||||
else
|
||||
scope.update_all(reflection.foreign_key => nil)
|
||||
scope.update_all(nullified_owner_attributes)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ module ActiveRecord
|
|||
target.destroy
|
||||
throw(:abort) unless target.destroyed?
|
||||
when :nullify
|
||||
target.update_columns(reflection.foreign_key => nil) if target.persisted?
|
||||
target.update_columns(nullified_owner_attributes) if target.persisted?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1815,6 +1815,22 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
|
|||
assert_equal num_accounts, Account.count
|
||||
end
|
||||
|
||||
def test_depends_and_nullify_on_polymorphic_assoc
|
||||
author = PersonWithPolymorphicDependentNullifyComments.create!(first_name: "Laertis")
|
||||
comment = posts(:welcome).comments.first
|
||||
comment.author = author
|
||||
comment.save!
|
||||
|
||||
assert_equal comment.author_id, author.id
|
||||
assert_equal comment.author_type, author.class.name
|
||||
|
||||
author.destroy
|
||||
comment.reload
|
||||
|
||||
assert_nil comment.author_id
|
||||
assert_nil comment.author_type
|
||||
end
|
||||
|
||||
def test_restrict_with_exception
|
||||
firm = RestrictedWithExceptionFirm.create!(name: "restrict")
|
||||
firm.companies.create(name: "child")
|
||||
|
|
|
@ -12,6 +12,9 @@ require "models/bulb"
|
|||
require "models/author"
|
||||
require "models/image"
|
||||
require "models/post"
|
||||
require "models/drink_designer"
|
||||
require "models/chef"
|
||||
require "models/department"
|
||||
|
||||
class HasOneAssociationsTest < ActiveRecord::TestCase
|
||||
self.use_transactional_tests = false unless supports_savepoints?
|
||||
|
@ -114,6 +117,21 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
|
|||
assert_nil Account.find(old_account_id).firm_id
|
||||
end
|
||||
|
||||
def test_nullify_on_polymorphic_association
|
||||
department = Department.create!
|
||||
designer = DrinkDesignerWithPolymorphicDependentNullifyChef.create!
|
||||
chef = department.chefs.create!(employable: designer)
|
||||
|
||||
assert_equal chef.employable_id, designer.id
|
||||
assert_equal chef.employable_type, designer.class.name
|
||||
|
||||
designer.destroy!
|
||||
chef.reload
|
||||
|
||||
assert_nil chef.employable_id
|
||||
assert_nil chef.employable_type
|
||||
end
|
||||
|
||||
def test_nullification_on_destroyed_association
|
||||
developer = Developer.create!(name: "Someone")
|
||||
ship = Ship.create!(name: "Planet Caravan", developer: developer)
|
||||
|
|
|
@ -4,5 +4,11 @@ class DrinkDesigner < ActiveRecord::Base
|
|||
has_one :chef, as: :employable
|
||||
end
|
||||
|
||||
class DrinkDesignerWithPolymorphicDependentNullifyChef < ActiveRecord::Base
|
||||
self.table_name = "drink_designers"
|
||||
|
||||
has_one :chef, as: :employable, dependent: :nullify
|
||||
end
|
||||
|
||||
class MocktailDesigner < DrinkDesigner
|
||||
end
|
||||
|
|
|
@ -62,6 +62,11 @@ class PersonWithDependentNullifyJobs < ActiveRecord::Base
|
|||
has_many :jobs, source: :job, through: :references, dependent: :nullify
|
||||
end
|
||||
|
||||
class PersonWithPolymorphicDependentNullifyComments < ActiveRecord::Base
|
||||
self.table_name = "people"
|
||||
has_many :comments, as: :author, dependent: :nullify
|
||||
end
|
||||
|
||||
class LoosePerson < ActiveRecord::Base
|
||||
self.table_name = "people"
|
||||
self.abstract_class = true
|
||||
|
|
|
@ -1257,7 +1257,7 @@ Controls what happens to the associated object when its owner is destroyed:
|
|||
|
||||
* `:destroy` causes the associated object to also be destroyed
|
||||
* `:delete` causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
||||
* `:nullify` causes the foreign key to be set to `NULL`. Callbacks are not executed.
|
||||
* `:nullify` causes the foreign key to be set to `NULL`. Polymorphic type column is also nullified on polymorphic associations. Callbacks are not executed.
|
||||
* `:restrict_with_exception` causes an `ActiveRecord::DeleteRestrictionError` exception to be raised if there is an associated record
|
||||
* `:restrict_with_error` causes an error to be added to the owner if there is an associated object
|
||||
|
||||
|
@ -1658,7 +1658,7 @@ Controls what happens to the associated objects when their owner is destroyed:
|
|||
|
||||
* `:destroy` causes all the associated objects to also be destroyed
|
||||
* `:delete_all` causes all the associated objects to be deleted directly from the database (so callbacks will not execute)
|
||||
* `:nullify` causes the foreign keys to be set to `NULL`. Callbacks are not executed.
|
||||
* `:nullify` causes the foreign key to be set to `NULL`. Polymorphic type column is also nullified on polymorphic associations. Callbacks are not executed.
|
||||
* `:restrict_with_exception` causes an `ActiveRecord::DeleteRestrictionError` exception to be raised if there are any associated records
|
||||
* `:restrict_with_error` causes an error to be added to the owner if there are any associated objects
|
||||
|
||||
|
|
Loading…
Reference in New Issue