Help us understand the problem. What is going on with this article?

【Laravel】リレーション後に外部キー設定を行う

More than 1 year has passed since last update.

リレーションと外部キー

以前、リレーションの作業を行なった。
【Laravel入門】リレーションとユーザーの一覧表示

そして、動作確認のためユーザーの削除を行ってみたが、予想と違う結果となった。自分の予想ではこうなるはずだったのに・・・

「ユーザーが削除されると、自動的にそのユーザーの投稿記事が削除される。」

しかし、削除されたユーザーに紐づく投稿記事が消えない。これは外部キーの設定を忘れていたためだった。ちなみに、自分の持つ外部キー関連の概念はこんなところだ。

  • ユーザーが保管されているusersテーブルと投稿記事が保管されているarticlesテーブルは、1対多の関係にある。
  • articlesテーブルはuser_idを元にusersテーブルから記事の作成者情報を得ている。この状態は、articlesテーブルが従テーブル、usersテーブルが主テーブルだと言える。
  • 従テーブルで主テーブルを参照するために使われるキーを外部キーと呼ぶ。

今回はその設定を行うことにした。

外部キー用のマイグレーションファイルを作成

上記の設定を行うためには、user_idを外部キーに設定しなければならない。

既存のcreate_articles_tableにその設定を書き加えて行く方法もあるらしいが、user_idは他のカラムと役割が違う。(それに記述が上手く出来ず、何回か失敗した;)

そのため、user_idの設定は独立したマイグレーションファイルadd_user_id_articles_tableに記述することにした。

create_articles_tableの編集

user_idを専用ファイルで作成するため、create_articles_tableから$table->integer('user_id');を削除した。

yyyy_mm_dd_hhmmss_create_articles_table.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateArticlesTable extends Migration
{
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->increments('id');
            // $table->integer('user_id');を削除
            $table->string('title');
            $table->string('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('articles');
    }
}

add_user_id_articles_tableの作成

add_user_id_articles_tableを新たに作成し、編集する。

$ php artisan make:migration add_user_id_articles_table
yyyy_mm_dd_hhmmss_add_user_id_articles_table.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddUserIdArticlesTable extends Migration
{
    public function up()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')
            ->references('id')->on('users')
            ->onDelete('cascade');
        });
    }

    public function down()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->dropForeign('articles_user_id_foreign');
        });
    }
}

内容を説明する。

up関数

  • Schemaファサードtableメソッドを使用する。
  • tableメソッドは第1引数にテーブル名、第2引数にBlueprintインスタンスの$tableを指定する。
  • $tableintegerメソッドuser_idを作成し、カラム修飾子unsignedメソッドを実行する。
  • unsignedメソッドはMySQLで整数カラムを符号なしに設定する。これを実行しないとエラーが発生するので注意すること。
  • foreignメソッドuser_idを外部キーに設定する。
  • referencesメソッドで、従テーブルのuser_idと紐付いている主テーブルのidを指定する。
  • onメソッドで主テーブルusersを指定する。
  • onDeleteメソッドuserが削除・更新された場合の処理を記述する。今回、引数はcascadeを指定する。

onDeleteメソッドには、以下4種類の引数がある。

  • cascade
  • set null
  • no action
  • restrict

詳細はこちらのサイト様から。
Laravel 5.3 Eloquent ORM 入門 2 (マイグレーション)

down関数

  • 外部キーを削除するためにはdropForeignメソッドを使用する。
  • dropForeignメソッドの引数は、命名規則によりテーブル名_外部キー名_foreignとなる。

動作確認

tableメソッドcreateメソッドと間違えたり、unsigned()を記述し忘れたり、途中でエラーの連続だった。

$ php artisan migrate:refresh
Rolling back: 2018_05_03_141933_create_articles_table
Rolled back:  2018_05_03_141933_create_articles_table
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table

In Connection.php line 664:

  SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'user_id' (SQL: alter table `a
  rticles` add `user_id` int not null)


In Connection.php line 458:

  SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'user_id'

何とかマイグレーションファイルを正しく編集し、migrationを実行できた。以下のコマンドでは、テーブルが存在しないのにrefreshしているため、最初にMigration table not found.と怒られている;

$ php artisan migrate:refresh
Migration table not found.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
Migrating: 2018_05_03_141933_create_articles_table
Migrated:  2018_05_03_141933_create_articles_table
Migrating: 2018_05_16_185519_add_user_id_articles_table
Migrated:  2018_05_16_185519_add_user_id_articles_table

これで、ユーザーを削除すると、そのユーザーに紐づく投稿記事も削除されるようになった。

今回はここまで。

yukibe
2018年8月よりWebエンジニア。主にPHP。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした