ポートフォリオ作成時メモ　part5 ~ユーザー登録画面の編集①~

## はじめに
こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して6ヶ月目に入りました。PHP,Laravelを学習しポートフォリオを作成中です。ポートフォリオ作成手順及び、エラー内容を中心に記録していこうと思います。今回はユーザー登録画面の編集を行いました。本投稿は流れのメモが重点になっておりますので、削除した部分や追加した部分の詳細は割愛致します。

## デフォルトの状態
Breezeインストール後のデフォルトの状態
![rejister_default.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/51729816-9b50-bec7-58b9-354ec039e828.png)


## 編集後の画面
![register_改善中2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/4b33dea6-cf5b-7c43-1c06-29615cc60caf.png)


## エラーが発生
- 添付のエラーが発生
![エラー3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/cd53c0a0-8bd8-1e4d-e338-07f76e1ea79e.png)
- エラー内容から原因を推測
推測原因①：genderの値が正しくサーバー側に渡されていない？
⇨性別を登録する部分を追加していたが、どこかのディレクトリで記述が漏れていた可能性あり
推測原因②：ジェンダーフィールドの値が適切にバリデーションや保存処理がされていない

## 調査内容
コントローラーでgenderフィールドがリクエストに含まれているか確認。
- **RegisteredUserController.php**のstoreメソッドで以下のコードを追加
```php
dd($request->all());
```
登録フォームを送信して、genderが正しい値を持っているか確認

## 調査結果
添付からgenderフィールドには値が渡されている
それにも関わらず下記のサーバーエラーが発生している
Internet Server Error 500
![スクリーンショット 2024-11-18 21.01.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/f92f1ad0-ce7a-adb0-2570-8fa89d495c11.png)

![スクリーンショット 2024-11-18 21.03.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/de4e61ba-5847-0a05-2ae5-5c93f27a7ea4.png)

## 調査内容2
モデルでジェンダーがfillableプロパティに含まれているか確認
⇨User.phpを確認したところ、含まれていなかった
下記にて修正したところ解決。
```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

```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

```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
<?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

```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>
```

## 次回実施内容
- 投稿画面の作成


最後までご覧いただき本当にありがとうございました！！