LoginSignup
1
0

More than 1 year has passed since last update.

dependent: :destroyオプションとActiveRecord::InvalidForeignKey (SQLite3::ConstraintException: FOREIGN KEY constraint failed)の対応方法について

Posted at

dependent: :destroyオプションとActiveRecord::InvalidForeignKey (SQLite3::ConstraintException: FOREIGN KEY constraint failed)について

dependent: :destroyオプションは、親モデルのデータが削除されるときにそれに関連していた子モデルのデータも削除することができるオプション。
このオプションを設定しないと、親モデルのテーブルのデータを削除するときにエラーになる。

20221001_ownersテーブルとcatsテーブルの画像.png

上記のようなテーブルがあり、ownersテーブルのid=3 高橋さんを削除すべく以下のコマンドを実行。

rails c コマンドの実行
irb(main):002:0> Owner.find(3).destroy
  TRANSACTION (0.1ms)  begin transaction
  Owner Destroy (3.0ms)  DELETE FROM "owners" WHERE "owners"."id" = ?  [["id", 3]]
  TRANSACTION (0.6ms)  rollback transaction
Traceback (most recent call last):
ActiveRecord::InvalidForeignKey (SQLite3::ConstraintException: FOREIGN KEY constraint failed)

エラー文は、「ActiveRecord::InvalidForeignKey (SQLite3::ConstraintException: FOREIGN KEY 制約が失敗しました)」という意味です。

つまり、親テーブルのownersテーブルにあるid=3 高橋さんを消そうとすると、外部キー制約(他のテーブルに参照・依存するようにカラムにつける制約のこと)により、データの整合性が保たれなくなり、id=3 高橋さんを参照している子テーブルcatsテーブルのid = 3 name = ハナ owner_id = 3のデータのowner_id を表示できなくなり、エラーになる。

そこでdependent: :destroyオプションを使用し、親モデルのデータが削除された時に子モデルのデータも一緒に削除できるようにし、データの整合性を保つようにする。

書き方は下記の通り。

owner.rb
class Owner < ApplicationRecord
  has_many :cats, dependent: :destroy
end

そして再度、ownersテーブルのid=3 高橋さんを削除すべく以下のコマンドを実行してみると、、、

irb(main):002:0> Owner.find(3).destroy
 Owner Load (0.2ms)  SELECT "owners".* FROM "owners" WHERE "owners"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
  TRANSACTION (0.1ms)  begin transaction
  Cat Load (0.2ms)  SELECT "cats".* FROM "cats" WHERE "cats"."owner_id" = ?  [["owner_id", 3]]
  Cat Destroy (0.5ms)  DELETE FROM "cats" WHERE "cats"."id" = ?  [["id", 3]]
  TRANSACTION (10.5ms)  commit transaction
=> #<Owner id: 3, name: "高橋", created_at: "2022-09-30 23:15:04.894767000 +0000", updated_at: "2022-09-30 23:15:04.894767000 +0000">

(Id = 3 高橋さんが消えたか確認)
irb(main):002:0> Owner.find(3)
  Owner Load (0.2ms)  SELECT "owners".* FROM "owners" WHERE "owners"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
Traceback (most recent call last):
ActiveRecord::RecordNotFound (Couldn't find Owner with 'id'=3)→id= 3高橋さんのデータ削除完了
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0