🙂
削除できない原因は外部キー制約だった。
概要
- 投稿を削除しようとしたらエラーが発生して削除できなかった
- PG::ForeignKeyViolation: ERROR: update or delete on table
- 外部キー制約が原因
実装の内容としては、
question
テーブル:1
solution
テーブル:多
この様に質問と回答の
2つのテーブルがあり、1対多の関係で紐づいていた。
PG::ForeignKeyViolation: ERROR: update or delete on table
エラーが起きた手順は以下の流れです。
- 質問を投稿
- 1でした投稿に回答を作成
- 質問を削除
- エラー発生
PG::ForeignKeyViolation: ERROR: update or delete on table
というエラーが発生して削除ができなかった。
(見たことがなかったので結構びびった。笑)
調べてみると、
外部キー制約というルールが原因でした。
外部キー制約を簡単に説明すると、
「他のテーブルのデータに参照(依存)するようにカラムにつける制約」
今回の件だと、
質問を削除してしまうと、それに紐づく回答も削除されてしまうけど大丈夫?
というエラーですね。
解決策
え?じゃあ回答がついてる質問は削除できないの?
と思いましたがそんなことはないですね。笑
- 各モデルに許可するコード書く。
- dependent オプションを使う。
dependent オプションについて詳しくはこちら&参照
destroy: 親と一緒に子レコードも削除する。(無理心中パターン)
delete_all: 親と一緒に子レコードも削除する。ただし、直接DBのレコードを削除するので、子レコードのコールバック処理は実行されない。
nullify: 子レコードの外部キーを NULL 更新する。(みなしごパターン)
restrict_with_exception: 子レコードがある場合は ActiveRecord::DeleteRestrictionError が発生する。(引き留めパターン)
restrict_with_error: 子レコードがある場合は削除できず、親レコードにエラー情報が付加される。(引き留めパターン)
今回だと
class Question < ApplicationRecord
has_many :solutions, dependent: :destroy
end
このようにモデルに追記することで削除できるようになった。
質問を消すと、その質問に紐づく回答も一緒に消して大丈夫だよ。というような意味ですね。
これで一件落着。
まとめ
アソシエーションがあるテーブルでは
外部キー制約も意識しないといけない。
dependent オプションの使い分けがまだ理解できていないのと
外部キー制約はこれからも使うことが多いと思うので
徐々に理解していく必要がある。
こちらの記事もオススメです。
Discussion