【Laravel】満足度評価のためのスター評価フォームの実装

## はじめに
よくある口コミの評価（スター）を実装しました。
評価については5段階評価となっています。

### 動作環境・使用するツールや言語

- OS バージョン
    - Windows11
- ツール
    - VSCode
- 言語
    - HTML&CSS
- フレームワーク
    - Laravel8
- スター
    - fontawesome v6.4.2

## 前提
- Laravelのセットアップは済んでいるものとする
- 例なので、簡単な構造での記事（中間テーブルなどは無し）
- DBは数字（``1～5``）の形で挿入される。

## 先に完成形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669894/5e53daee-4401-0d44-4a87-df28071982cb.png)
- スターが5つ並んでいて、一番左が1、右に大きくなるにつれ数字が上がり、一番右は5。
- ホバーすると色が変わる。
例えば、「``3``」にホバーすると、``1、2、3``の色が変わる仕様。
- クリック時にも当然色が変わる。


## マイグレーションファイルとモデル
```PHP:create_ratings_table.php
public function up()
{
    Schema::create('ratings', function (Blueprint $table) {
        $table->id();
        $table->unsignedTinyInteger('rating')->default(0)->nullable(false);
        $table->timestamps();
    });
}
```
- ``unsignedTinyInteger``で``0～255``と限られた範囲での使用（今回使うのは0～5）
- ``unsigned``で負の値NG
- ``default(0)``でデフォルトを0に設定。1～5だとバグの判別難しいため
- ``nullable(false)``でnullはもちろん許容しない


## フォームリクエスト
``` PHP:RatingRequest.php
public function rules()
{
    return [
        'rating' => 'required|integer|min:1|max:5',
    ];
}

public function messages()
{
    return [
        'rating.required' => '評価は必須項目です',
        'rating.integer' => '評価は整数を指定してください',
        'rating.min' => '評価には1以上の数値を指定してください',
        'rating.max' => '評価には5以下の数値を指定してください',
    ];
}
```
- 入力必須、整数、1～５のみ許容

## ルーティング
```PHP:web.php
Route::get('/', [RatingController::class, 'index'])->name('test');
Route::post('/store', [RatingController::class, 'store'])->name('store');
```


## ビュー（HTML&CSS）
```HTML:test.blade.php
<form action="{{ route('store') }}" class="form" method="post">
    @csrf
    <p class="form-title">満足度</p>
    <div class="form-rating">
        <input class="form-rating__input" id="star5" name="rating" type="radio" value="5">
        <label class="form-rating__label" for="star5"><i class="fa-solid fa-star"></i></label>

        <input class="form-rating__input" id="star4" name="rating" type="radio" value="4">
        <label class="form-rating__label" for="star4"><i class="fa-solid fa-star"></i></label>

        <input class="form-rating__input" id="star3" name="rating" type="radio" value="3">
        <label class="form-rating__label" for="star3"><i class="fa-solid fa-star"></i></label>

        <input class="form-rating__input" id="star2" name="rating" type="radio" value="2">
        <label class="form-rating__label" for="star2"><i class="fa-solid fa-star"></i></label>

        <input class="form-rating__input" id="star1" name="rating" type="radio" value="1">
        <label class="form-rating__label" for="star1"><i class="fa-solid fa-star"></i></label>
    </div>
    @error('rating')
    <p class="error">{{ $message }}</p>
    @enderror
    <button type="submit">送信</button>
</form>
```




```CSS:test.css
.form-rating {
    align-items: center;
    display: flex;
    flex-direction: row-reverse;
    justify-content:flex-end;
    margin-bottom: 20px;
}
.form-rating__input {
    display: none;
}
.form-rating__label {
    color: #ccc;
    cursor: pointer;
    font-size: 24px;
    padding: 0 10px;
    position: relative;
    transition: color 0.3s;
}
.form-rating__label:hover,
.form-rating__label:hover ~ .form-rating__label,
.form-rating__input:checked ~ .form-rating__label {
    /* 「~」でホバー時を動的に、チェック時にそれ以下の数字をもつスターの色も変化 */
    color: #c4c403;
}
.error {
    color: #ff6200;;
}
```

## コントローラー
```PHP:RatingController
public function index()
{
    return view('test');
}

public function store(RatingRequest $request)
{
    $rating = $request->input('rating');
    $reviewData = [
        'rating' => $rating,
    ];
    Rating::create($reviewData);

    return redirect()->route('test');
}
```


## 主要なつまずいた所

１．**送信ボタンを押すと、``/store``で「403 | THIS ACTION IS UNAUTHORIZED.」が出現。**
- 「このアクションは許可されていません。」とのこと。

### 考えたこと・実行したこと
- 素直に捉えて、ファイル権限がない？
    - ``sudo chmod -R 777 src/*``を実行するも解決せず。
- ``/store``でエラーが発生しているため、ルートは問題ない。
- ``return redirect()->route('test');``か？問題ない。
- そもそもフォームは送れているのか？
    - ``dd($request);``するも、変わらず403エラー。
- フォームリクエストか？
    - 解決

### 解決方法
```PHP:RatingRequest.php
public function authorize()
{
    return false;
}
```
単純に、``false``を返していたことが原因でした。
``true``に修正すると、期待通りの動作になりました。

いやーこんなところで、、、お恥ずかしい。
最近はあまり意識できていなかったせいか、初めてここで時間を使いました。
まあ今後気を付けていきましょ