はじめに
エンジニア転職を目指し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カラムは書籍の評価を整数の値で表します。
その後作成されたマイグレーションファイルを以下のように編集します。
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カラムが追加されているか確認します。
$ 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.モデルを編集する
まずはバリデーションを追加します。
class Book < ApplicationRecord
validates :title, presence: true
validates :author, presence: true
validates :rating, presence: true
end
enumを使ってステータスを定義します。
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についてはこちら
3.コントローラを編集する
booksコントローラのストロングパラメーターにratingカラムを追加します。
private
def book_params
params.require(:book).permit(:title, :author, :rating)
end
4.viewを編集する
(1)投稿フォームを編集
投稿フォームに以下を追記します。
<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(評価の値)を使ってループ処理をしています。
星のcssスタイリングはdaisyUIの公式ページを参考にしてください
投稿フォームは以下のようになりました。
<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>
(2)投稿一覧に評価を表示させる
投稿の一覧ページに評価を表示させるために以下を追記します。
<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)にしているます。これによって、評価に応じた星が表示されるようにしています。
- マイグレーションファイル編集時に
default: 1にしたので元々あるレコードは評価1

