環境:Laravel 6.2
検索した感じでは8でも変わってないはず、、
状況
ユーザーの退会処理を作ろうと思い、$user->delete();
を行ったところ下記のエラーが出た
Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails
ユーザーが投稿した記事(articlesテーブル)が外部キーでユーザーと紐づいているため、
先に該当ユーザーが投稿した記事を削除しないとエラーが出てしまうようだ
対応案
ユーザーの退会処理を行うメソッド内で、先に記事削除の処理を書けば一応解決はする。
しかし、articlesテーブルの外部キーにonDelete cascadeを設定してやれば、そのあたり自動でやってくれるので、今回はそちらを行うことにした。
onDelete cascade追加用のマイグレーションファイル作成
articlesテーブルの中身がすべて消えても良いなら
ロールバックしてarticlesテーブル作成用のマイグレーションファイルを書き直せば良いが
今回は消したくなかったので、onDelete cascade追加用のマイグレーションファイルを新たに作成した。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddCascadeToUserIdOnArticleTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->dropForeign(['user_id']);//いったん外部キーを削除する。
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('articles', function (Blueprint $table) {
$table->dropForeign(['user_id']);
$table->foreign('user_id')
->references('id')->on('users');
});
}
}
注意点としては、上記コードupメソッド内のコメントにも書いているが
先に外部キーを削除する必要があるので、upメソッド内に$table->dropForeign(['user_id']);
を記述していること。
ちなみにこのdropForeignの引数は、本来であれば「リレーション元のテーブル名_外部キーを設定しているカラム名_foreign」なので、dropForeign(articles_user_id_foreign)となるが、今回のようにリレーション先のテーブル名(users)に対して、外部キーを設定しているカラム名がuser_id(usersの単数形+_id)といった形で、Laravelの命名ルールに則っている場合は、上記コードのようにdropForeign(['user_id'])
という書き方もできる。
確認
もちろん$user->delete();
を行えば動作確認はできるし、
phpmyadminでの確認やコマンドでDBにログインしての確認もできる。
ちなみに
onDelete cascade は「連動して削除する」だが
onDelete restrict は「連動せず、削除を制限する(エラーが出る)」。restrictがデフォルト。