When building the following parent-child relationships with reference When deleting the data of the parent model, I want to register the foreign key with nil without deleting the child product data, but when I delete the parent from the console, an error occurs and I do not know how to deal with it. is. -Parent model: "Category" ・ Child model: "Product"
20201211121059_create_products.rb
t.references :category, null: false, foreign_key: true
It was carried out with reference to the following articles. optional: How to allow nil if set to true https://techtechmedia.com/optional-true-rails/#optional_true https://qiita.com/takuyanin/items/6f6be86d1265be21bf9e
Like this, I added dependent and optionl options to has_many and belongs_to.
catedory.rb
class Category < ApplicationRecord
has_many :products, dependent: :nullify
end
product.rb
class Product < ApplicationRecord
belongs_to :category, optional: true
end
In this state, register parent and child data from the console.
Example category = Category.create!(....) category.products.create!(....)
Execute Category.destroy_all as a trial. The child's foreign key is registered as nil, right? I get the following error and have trouble dealing with it.
ActiveRecord::NotNullViolation: Mysql2::Error: Column 'category_id' cannot be null
Also, when creating a new child model data with the foreign key nil, the error is different depending on whether optional: true is set/not set.
- At the time of setting ActiveRecord::NotNullViolation: Mysql2::Error: Field 'category_id' doesn't have a default value
- Not set ActiveRecord::RecordInvalid: Validation failed: Category must exist
Optional: true in the first place? If set to true, validation can be passed even if the foreign key does not contain a value. ↑ ** In other words, the problem is validation ** (If the default is not set, it is false, so validation is executed.)
(Rails db: rollback is also possible with up, down notation)
class ChangeReferencesIdToProducts < ActiveRecord::Migration[6.0]
def up
change_column :products, :category_id, :bigint, null: true
end
def down
change_column :products, :category_id, :bigint, null: false
end
end
It was caused by null: false, so by changing it to null: true The child's foreign key is now registered with nil even if the parent is deleted.
I hope it helps someone.