みなさん、こんにちは!
アプリを完成しましたが、データの削除の際に外部キーのエラーがあったので修正しようとしたところ、地獄を見たので愚痴らせてください。
サービスについてはこちら
laravel学んで2か月で自サービスを開発した話 Part1
何が起きたか
はい、外部キーの参照エラーです。
まあ、これは予想通りだったので、じゃけん直していこうね
注意!ここからは私の試行錯誤が含まれます。真似すると地獄を見ますのでやめましょう!
マイグレーションファイルを直接編集する
とりあえず、マイグレーションファイルを編集してphp artisan migrateすればええやろ!
Schema::create('processed_products', function (Blueprint $table) {
$table->id();
$table->foreignId('admin_id')->constrained('admins');
$table->foreignId('product_id')->constrained();
$table->foreignId('product_id')
->onUpdate('cascade')
->onDelete('cascade')
->constrained('products');
$table->boolean('result');
$table->timestamps();
});
cascadeを付けて変更すればええやん!それで、php artisan migrate っと
nothing migration
あ、あれっ?変更が反映されないぞ?
まあ、もしかしたら、変更がされているかもしれないし、削除ボタンと
知ってた
データベースを直接編集する
マイグレーションファイルが編集できないんだったら、データベースを直接編集すればええやん!
ということで、データーベースの外部キーをRESTRICTからCASCADEに変更してと・・・
これなら大丈夫でしょ!
33-4
さすがに知り合いに聞いてみた。
エンジニアさん「このエラーに関してどんなアプローチをしたんですか?」
マイグレーションファイルとデータベースの値を直接変更しちゃった
エンジニアさん「今から緊急会議です。ZOOMつないでください。」
ええええええええええええ!!
結局何がいけなかったのか
エンジニアさんと実際に話してみてわかったことが
- マイグレーションファイルは編集せずに、データベースに変更を加えるときは新しいマイグレーションファイルを作る
- データベースを直接いじらない
- データベースとマイグレーションの状況を合わせる
ということらしいので、さっそく助言もいただきながら修正してみた。
マイグレーションファイルの作成
すでにあるマイグレーションファイルをいじるのはご法度なので、マイグレーションファイルを作成します
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ProcessedCommentsTableDropForeign extends Migration
{
public function up()
{
Schema::table('processed_comments', function (Blueprint $table) {
$table->dropForeign('processed_comments_comment_id_foreign');
});
}
public function down()
{
Schema::table('processed_comments', function (Blueprint $table) {
$table->foreign('comment_id')->references('id')->on('comments');
});
}
}
このマイグレーションファイルを更新して既にある外部キーをドロップします
しかし、upメゾットだけだと、更新時にエラーが起きた時、完全性が損なわれるので、downメゾットにはupメゾットの逆のことを書いていきます
この場合だと、外部キーをつける工程をdownメゾットに書きます
この逆のメゾットを考えるのが難しかった・・・
また、勝手にデータベースをいじってcascadeをつけてしまった分を補完するマイグレーションファイルを作ります
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ChangeForeignkeyRestrictToCascade extends Migration
{
public function up()
{
Schema::table('processed_products', function (Blueprint $table) {
$table->dropForeign('processed_products_product_id_foreign');
});
Schema::table('processed_comments', function (Blueprint $table) {
$table->foreign('comment_id')->references('id')->on('comments')
->onUpdate('cascade')
->onDelete('cascade');
});
Schema::table('processed_products', function (Blueprint $table) {
$table->foreign('product_id')->references('id')->on('products')
->onUpdate('cascade')
->onDelete('cascade');
});
}
public function down()
{
Schema::table('processed_products', function (Blueprint $table) {
$table->dropForeign('processed_products_product_id_foreign');
$table->foreign('product_id')->references('id')->on('products');
});
Schema::table('processed_comments', function (Blueprint $table) {
$table->dropForeign('processed_comments_comment_id_foreign');
});
}
}
この状態でphp artisan migrate していきます
データベースにマイグレーションファイルを手動で追加
この状態で php artisan migrate:status でマイグレーションの状況を確認すると
なぜNOになっているかというと、データベースにさっきの2つのマイグレーションファイルがないからです
データベースをいじくってLaravelをだまします
どういうことかというと、
これで再び php artisan migrate:status をすると2つのマイグレーションファイルがyesになります!
これでマイグレーションとLaravelの整合性が保たれました!
今度こそ凍結された商品を削除しましょう!
やったぜ
終わりに
マイグレーションは一方通行だから、絶対に編集しちゃだめだぞ!
また、データベースも直接いじらず、マイグレーションファイルから指令を出しましょう!