daisyUIを用いてレーティング機能(星5評価機能)を実装してみた

## はじめに
エンジニア転職を目指しRuby on Railsを中心に学習中の初学者です。
ポートフォリオにレーティング機能を実装したので、その備忘録として書き記しておきます。
ちなみに、**jQueryプラグインであるRaty.jsは使用していません**。
誤っている箇所や改善点などありましたらご指摘いただけると幸いです。

## 開発環境
- docker環境
- ruby:3.3.6
- ruby on rails: 7.2
- tailwindcss: 4.0.15
- daisyui: 5.0.9

## 前提
- CSSライブラリのdaisyUIはすでにインストールされている状態とします
- 小説に対して星評価をします

## 1.テーブルにratingカラムを追加する
Bookテーブルにraitngカラムを追加します。
```
$ docker compose exec web rails g migration AddRatingToBooks rating:integer
```
ratingカラムは書籍の評価を整数の値で表します。
その後作成されたマイグレーションファイルを以下のように編集します。
```Ruby
class AddRatingToBooks < ActiveRecord::Migration[7.2]
  def change
    add_column :books, :rating, :integer, null: false, null: false, default: 1
  end
end
```
`rating`カラムに`null: false`を指定しているけど、すでに存在するレコードがある場合、デフォルト値を設定しないとエラーになる可能性がある。

なので`default`オプションを使ってデフォルト値を設定します。

その後以下を実行
```
docker compose exec web rails db:migrate 
```

念のため、コンソールで`rating`カラムが追加されているか確認します。

```Ruby
$ docker compose exec web rails c --sandbox

> Book.first
=> 
#<Book:0x0000ffff7c3c98b8
 id: 1,
 title: "そして誰もいなくなった",
 author: "アガサクリスティー",
 created_at: "2025-04-25 07:50:42.467174000 +0000",
 updated_at: "2025-04-25 07:50:42.467174000 +0000",
 rating: 1>
 ```

 ## 2.モデルを編集する
 まずはバリデーションを追加します。
 ```Ruby
 class Book < ApplicationRecord
  validates :title, presence: true
  validates :author, presence: true
  validates :rating, presence: true
end
```

`enum`を使ってステータスを定義します。
```Ruby
class Book < ApplicationRecord
  validates :title, presence: true
  validates :author, presence: true
  validates :rating, presence: true

  # 星5評価のステータス
  enum rating: {
    very_poor: 1,
    poor: 2,
    fair: 3,
    good: 4,
    excellent: 5
  }
end
```

`enum`を使うことで、可読性が高く、コードが管理しやすくなります。

`enum`については[こちら](https://railsguides.jp/active_record_querying.html#enum)

## 3.コントローラを編集する
booksコントローラのストロングパラメーターにratingカラムを追加します。

```Ruby
  private

  def book_params
    params.require(:book).permit(:title, :author, :rating)
  end
```

## 4.viewを編集する

### (1)投稿フォームを編集
投稿フォームに以下を追記します。

```Ruby
<div>
  <%= f.label :rating %>
  <div class="rating">
    <% Book.ratings.each do |key, value| %>
      <%= f.radio_button :rating, key, class: "mask mask-star-2 bg-orange-400" %>
    <% end %>
  </div>
</div>
```

- `<% Book.ratings.each do |key, value| %>`

さきほどBookモデルに`enum rating`を定義したので`Book`モデルのインスタンスで`ratings`メソッドを使うことができ、定義した`enum rating`の一覧を取得できるようになります。
つまり`Book`モデルの`ratings`メソッドから各評価を取得して、それぞれの`key`（評価の表示名）と`value`（評価の値）を使ってループ処理をしています。

:::note info
星のcssスタイリングはdaisyUIの[公式ページ]()を参考にしてください
:::

投稿フォームは以下のようになりました。
```Ruby
<div>
  <%= form_with model: @book, local: true do |f| %>
    <div class="mb-5">
      <%= f.label :title %>
      <%= f.text_field :title, placeholder: "タイトル", class: "border" %>
    </div>

    <div class="mb-5">
      <%= f.label :author %>
      <%= f.text_field :author, placeholder: "著者", class: "border" %>
    </div>

    # レーティング
    <div class="mb-5">
      <%= f.label :rating %>
      <div class="rating rating-md space-x-2">
        <% Book.ratings.each do |key, value| %>
          <%= f.radio_button :rating, key, class: "mask mask-star-2 bg-orange-400" %>
        <% end %>
      </div>
    </div>

    <div class="mb-5 btn">
      <%= f.submit "投稿する" %>
    </div>
  <% end %>
</div>
```

![00c57e9f37b74a02dac5de6aac6538b8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4072077/dfb36bcd-99bf-4532-9faf-48a1f457f493.gif)

### (2)投稿一覧に評価を表示させる

投稿の一覧ページに評価を表示させるために以下を追記します。
```Ruby
<div class="flex">
  <h4 class="card-title">評価: </h4>
  <div class="flex space-x-1 items-center ml-2">
    <% Book.ratings.length.times do |index| %>
      <span class='inline-block h-5 w-5 mask mask-star-2 <%= index < Book.ratings[book.rating] ? "bg-orange-400" : "bg-stone-400" %>' aria-hidden="true">
      </span>
    <% end %>
  </div>
</div>
```

- `<%= index < Book.ratings[book.rating] ? "bg-orange-400" : "bg-stone-400" %>`

`index`が評価（`book.rating`）より小さい場合はオレンジ色（`bg-orange-400`）、それ以外はグレー色（`bg-stone-400`）にしているます。これによって、評価に応じた星が表示されるようにしています。

![5107d24206836c24fcb5aa41f2987c5c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4072077/da8d1be8-9a18-41bc-bf7d-6306058a8674.png)

- マイグレーションファイル編集時に`default: 1`にしたので元々あるレコードは評価１