はじめに
こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して6ヶ月目に入りました。PHP,Laravelを学習しポートフォリオを作成中です。ポートフォリオ作成手順及び、エラー内容を中心に記録していこうと思います。今回はユーザー登録画面の編集を行いました。本投稿は流れのメモが重点になっておりますので、削除した部分や追加した部分の詳細は割愛致します。
デフォルトの状態
編集後の画面
エラーが発生
- 添付のエラーが発生
- エラー内容から原因を推測
推測原因①:genderの値が正しくサーバー側に渡されていない?
⇨性別を登録する部分を追加していたが、どこかのディレクトリで記述が漏れていた可能性あり
推測原因②:ジェンダーフィールドの値が適切にバリデーションや保存処理がされていない
調査内容
コントローラーでgenderフィールドがリクエストに含まれているか確認。
- RegisteredUserController.phpのstoreメソッドで以下のコードを追加
dd($request->all());
登録フォームを送信して、genderが正しい値を持っているか確認
調査結果
添付からgenderフィールドには値が渡されている
それにも関わらず下記のサーバーエラーが発生している
Internet Server Error 500
調査内容2
モデルでジェンダーがfillableプロパティに含まれているか確認
⇨User.phpを確認したところ、含まれていなかった
下記にて修正したところ解決。
protected $fillable = [
'name',
'email',
'password',
'account_name',
'instagram',
'gender',
'location',
'profile_photo',
];
補足情報
- fillable の役割
fillable プロパティは、Eloquent の「一括代入 (Mass Assignment)」を使用する際に、どのフィールドを許可するかを指定します。このプロパティに指定していないフィールドは、自動的に無視されるため、データベースに保存されません。
今回のケースでは gender が fillable に追加されていなかったため、データベースに挿入されず、NOT NULL 制約によってエラーが発生していました。
変更した部分
app/Http/Controllers/Auth/RegisteredUserController.php
// リクエスト内容を確認
// dd($request->all());
// バリデーション
$request->validate([
'account_name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
'instagram' => 'nullable|string|max:255',
// 'gender' => 'required|string',
'gender' => 'required|in:male,female',
'location' => 'nullable|string|max:255',
'profile_photo' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
]);
// プロフィール写真の保存処理
$profilePhotoPath = null;
if ($request->hasFile('profile_photo')) {
$profilePhotoPath = $request->file('profile_photo')->store('profile_photos', 'public');
}
// ユーザー作成
$user = User::create([
'account_name' => $request->account_name,
'name' => $request->account_name, // ここで `name` を設定
'email' => $request->email,
'password' => Hash::make($request->password),
'instagram' => $request->instagram,
'gender' => $request->gender, //この部分は正しい。
'location' => $request->location,
'profile_photo' => $profilePhotoPath,
]);
// 登録イベント発火
event(new Registered($user));
// ログイン処理
Auth::login($user);
// ダッシュボードへのリダイレクト
return redirect()->route('dashboard');
}
}
app/Models/User.php
protected $fillable = [
'name',
'email',
'password',
'account_name',
'instagram',
'gender',
'location',
'profile_photo',
];
database/migrations/2024_11_17_205314_add_fields_to_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('account_name')->nullable()->after('id'); // NULLを許容する
$table->string('instagram')->nullable()->after('email');
$table->string('gender')->after('instagram');
$table->string('location')->nullable()->after('gender'); // locationカラムを追加
$table->string('profile_photo')->nullable()->after('location');
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['account_name', 'instagram', 'gender', 'location', 'profile_photo']); // locationを含むすべてのカラムを削除
});
}
};
resources/views/auth/register.blade.php
<x-guest-layout>
<div class="flex justify-center items-center min-h-screen bg-gray-100">
<div class="w-full max-w-md bg-white p-6 rounded-lg shadow-md">
<h2 class="text-center text-2xl font-bold mb-6">ユーザー登録</h2>
<form method="POST" action="{{ route('register') }}" enctype="multipart/form-data" class="space-y-6">
@csrf
<!-- アカウント名 -->
<div>
<x-input-label for="account_name" :value="__('アカウント名')" />
<x-text-input id="account_name" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500" type="text" name="account_name" required autofocus />
<x-input-error :messages="$errors->get('account_name')" class="mt-2" />
</div>
<!-- メールアドレス -->
<div>
<x-input-label for="email" :value="__('メールアドレス')" />
<x-text-input id="email" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500" type="email" name="email" required />
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
<!-- パスワード -->
<div>
<x-input-label for="password" :value="__('パスワード')" />
<x-text-input id="password" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500" type="password" name="password" required />
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
<!-- パスワード(確認用) -->
<div>
<x-input-label for="password_confirmation" :value="__('パスワード(確認用)')" />
<x-text-input id="password_confirmation" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500"
type="password"
name="password_confirmation"
required autocomplete="new-password" />
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
</div>
<!-- Instagram URL -->
<div>
<x-input-label for="instagram" :value="__('Instagram URL')" />
<x-text-input id="instagram" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500" type="text" name="instagram" />
<x-input-error :messages="$errors->get('instagram')" class="mt-2" />
</div>
<!-- 性別 -->
<div>
<x-input-label for="gender" :value="__('性別')" />
<select id="gender" name="gender" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500">
<option value="male">男</option>
<option value="female">女</option>
</select>
<x-input-error :messages="$errors->get('gender')" class="mt-2" />
</div>
<!-- 写真 -->
<div>
<x-input-label for="profile_photo" :value="__('写真を選択')" />
<input id="profile_photo" class="block mt-1 w-full border-gray-300 rounded-lg shadow-sm focus:border-indigo-500" type="file" name="profile_photo" accept="image/*">
<x-input-error :messages="$errors->get('profile_photo')" class="mt-2" />
</div>
<!-- 登録ボタン -->
<div class="flex justify-center">
<x-primary-button class="w-full text-center">
{{ __('登録') }}
</x-primary-button>
</div>
</form>
</div>
</div>
</x-guest-layout>
次回実施内容
- 投稿画面の作成
最後までご覧いただき本当にありがとうございました!!