🆔

【Laravel】usersテーブルのidをULIDに変更する方法とログイン出来なくなる問題の解決方法

2024/07/25に公開

こんにちは、saitogoです。
今回はusersテーブルのidをULIDに変更する方法について記事にまとめました。

ゴール

usersテーブルでidの代わりにULIDを使用する。

開発環境

  • Windows11
  • WSL2
  • Docker
  • Laravel 11.9
  • VScode

前提

  • Laravelの開発環境は既に構築済み
  • Authファザードを使ったログイン処理が実装済み

結論

0001_01_01_000000_create_users_table.php
<?php

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

return new class extends Migration
{
	protected $keyType = "string"; // primary key type
	public $incrementing = false; // auto incrament

	/**
	 * Run the migrations.
	 */
	public function up(): void
	{
		Schema::create('users', function (Blueprint $table) {
			// $table->id();
			$table->ulid("id")->primary();
			// $table->string('name');
			$table->string('email')->unique();
			// $table->timestamp('email_verified_at')->nullable();
			$table->string('password');
			$table->rememberToken();
			$table->timestamps();
		});

		Schema::create('password_reset_tokens', function (Blueprint $table) {
			$table->string('email')->primary();
			$table->string('token');
			$table->timestamp('created_at')->nullable();
		});

		Schema::create('sessions', function (Blueprint $table) {
			$table->string('id')->primary();
			$table->foreignUlid('user_id')->nullable()->index();
			$table->string('ip_address', 45)->nullable();
			$table->text('user_agent')->nullable();
			$table->longText('payload');
			$table->integer('last_activity')->index();
		});
	}

	/**
	 * Reverse the migrations.
	 */
	public function down(): void
	{
		Schema::dropIfExists('users');
		Schema::dropIfExists('password_reset_tokens');
		Schema::dropIfExists('sessions');
	}
};

やったこと

usersテーブルのSchemaをidからulidに変更。
※nameとemail_verified_atは使用しないのでコメントアウトしてます。

0001_01_01_000000_create_users_table.php
Schema::create('users', function (Blueprint $table) {
	// $table->id();
	$table->ulid("id")->primary();
	// $table->string('name');
	$table->string('email')->unique();
	// $table->timestamp('email_verified_at')->nullable();
	$table->string('password');
	$table->rememberToken();
	$table->timestamps();
});

Auth::attemptはtrueを返すが、ログイン状態が保持されていなかった。
そのためリダイレクト後にログイン画面に戻されてしまう。

原因

sessionsテーブルの外部キー制約の型が不一致のため、sessionsのuser_idカラムがNULLになってしまい、ログイン情報が参照出来なかった。

詳細

sessionsテーブルの外部キー制約のデフォルトはidの型を使ってる。
つまり、user_idの型はbigint(20)になっている。

0001_01_01_000000_create_users_table.php
Schema::create('sessions', function (Blueprint $table) {
	$table->string('id')->primary();
 	$table->foreignId('user_id')->nullable()->index();
	$table->string('ip_address', 45)->nullable();
	$table->text('user_agent')->nullable();
	$table->longText('payload');
	$table->integer('last_activity')->index();
});

しかし、ULID(usersテーブルのidカラム)の型はchar(26)です。
そのためbigint(20)char(26)で型が不一致となり、sessionsテーブルのuser_idカラムの値はNULLになってしまう。

usersテーブルの構造 sessionsテーブルの構造
usersテーブルの構造 sessionsテーブルの構造

解決方法

sessionsテーブルのSchemaのforeignIdforeignUlidに変更する。

0001_01_01_000000_create_users_table.php
Schema::create('sessions', function (Blueprint $table) {
	$table->string('id')->primary();
-	$table->foreignId('user_id')->nullable()->index();
+	$table->foreignUlid('user_id')->nullable()->index();
	$table->string('ip_address', 45)->nullable();
	$table->text('user_agent')->nullable();
	$table->longText('payload');
	$table->integer('last_activity')->index();
});

補足

UUIDを使いたい場合は上記のULIDをUUIDに変更するだけで使える。

0001_01_01_000000_create_users_table.php
Schema::create('users', function (Blueprint $table) {
	// $table->id();
-	$table->ulid("id")->primary();
+	$table->uuid("id")->primary();
	// $table->string('name');
	$table->string('email')->unique();
	// $table->timestamp('email_verified_at')->nullable();
	$table->string('password');
	$table->rememberToken();
	$table->timestamps();
});

Schema::create('sessions', function (Blueprint $table) {
	$table->string('id')->primary();
-	$table->foreignUlid('user_id')->nullable()->index();
+	$table->foreignUuid('user_id')->nullable()->index();
	$table->string('ip_address', 45)->nullable();
	$table->text('user_agent')->nullable();
	$table->longText('payload');
	$table->integer('last_activity')->index();
});

おわりに

usersテーブルの主キーをULIDに変更する記事はたくさんありますが、どの記事もusersテーブルのSchemaを変更することしか書いてなかったので、ログイン出来ずにハマってしまいました。

デフォルトのIDだと連番なので、ユーザー数やユーザーIDが推測出来てしまうため、今回IDをULIDに変更する記事を書きました。

今回Zennで記事を投稿するのが初めてなので、至らないところがあれば指摘していただけると幸いです。

GitHubで編集を提案

Discussion