【Rails】 投稿時の星5段階評価機能の実装

2023/06/08に公開

5段階評価の実装

要件

・自身の投稿にのみ、5段階評価をつけられ、評価をつけられるタイミングは、投稿時に限定。
・本の一覧ページと詳細ページに5段階評価を表示させる。
・ユーザーの詳細ページに 5 段階評価を表示させる。
・一度評価をつけたら変えられない。(Edit ページにも星は表示されるが、変更不可)

前提

・ jQuery のインストールがされている。

5段階評価の実装方法

様々な方法があるようですが、今回は JavaScript で作成されたプラグインである Raty を使用し、最新バージョンである Raty 4系で実装を行います。

Ratyの利用手順

  1. githubよりダウンロードしてください。(https://github.com/wbotelhos/raty)
  2. ダウンロードしたら、raty/src/imagesの中にある下記3つのスターの画像を自分のapp/assets/imagesフォルダに格納します。
    ・star-half.png
    ・star-on.png
    ・star-off.png
  3. src/raty.jsapp/javascriptにコピーします。
  4. app/javascript/packs/application.jsに下記を追加します。
app/javascript/packs/application.js
import Raty from "raty.js"
window.raty = function(elem,opt) {
  let raty =  new Raty(elem,opt)
  raty.init();
  return raty;
}

このコードは、raty.jsという JavaScript ライブラリから Raty というオブジェクトをインポートして、グローバル変数の window.raty に設定している。

windowオブジェクトとは
・画面上に表示されているすべてのオブジェクトの親となるオブジェクト
・JavaScript のオブジェクト階層の最上位に位置する。
・ウィンドウに関する情報の取得や、ウィンドウを設定・操作する。

function(関数)とは
・様々な処理を1つにまとめて、名前をつけることができるもの。
・単調な処理を1つにまとめて、どこからでも使えるように効率化するという目的で使われている。

"star"カラムの追加

terminal
rails g migration AddStarToBooks star:string

booksテーブルに string 型の star カラムの追加します。

terminal
rails db:migrate

ストロングパラメーターへ star カラムを追記する

controllers/books_controller.rb
private

  def book_params
    params.require(:book).permit(:title, :body, :star)#ここのstar
  end
end

permit メソッドへ追記することで'star'が保存できるようになります。

view への記述

indexとeditで使用される部分テンプレート

books/_form.html.erb
:
<% if book.id.nil? %>
    <div class="form-group" id="star">
      <%= f.label :star %>
      <%= f.hidden_field :star, id: :review_star, class: 'form-control' %>
      <div id="post_raty"></div>
    </div>
    <script>
      $(document).on('turbolinks:load', function() {
        let elem = document.querySelector('#post_raty');
        if (elem == null) return;
  
        elem.innerHTML = ""
        let opt = {  
          starOn: "<%= asset_path('star-on.png') %>",
          starOff: "<%= asset_path('star-off.png') %>",
          starHalf: "<%= asset_path('star-half.png') %>",
          scoreName: 'book[star]',
        };
        raty(elem, opt);
      });
    </script>
  <% else %>
    <div class="form-group">
      <%= render "static.rate", book: book %>
    </div>
<% end %>

新しく投稿をするときには、評価の星の評価を追加するために Raty プラグインが使用され、既存の投稿の場合は下記の_static.rateファイルが使用されます。

_static.rate.html.erb
<div id="star_<%= book.id %>"></div>
<script>
$(document).on('turbolinks:load', function() {
  let elem = document.querySelector('#star_<%= book.id %>');
  if (elem == null) return;
  
  elem.innerHTML = "";
  let opt = {  
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    starHalf: "<%= asset_path('star-half.png') %>",
    score: "<%= book.star %>",
    readOnly: true,    #readOnlyパラメータが設定されているため、ユーザーは評価を変更できない
  };
  raty(elem, opt);
});
</script>

投稿のIDに応じて異なるスターの評価を表示するために使用されます。
div タグは、投稿のIDに基づいて動的に生成され、スクリプトでは、それをターゲットとして使用。最後に、評価値、readOnly オプションなどが設定された Raty プラグインをインスタンス化する。これにより、ユーザーがその投稿につけた評価が表示されます。

必要な箇所に部分テンプレートを記述

_index.html.erb
<%= render "books/static.rate", book: book %>
books/show.html.erb
<%= render 'form', book: Book.new %><%= render "static.rate", book: @book %>
books/edit.html.erb
<%= render 'form', book: @book %>
books/index.html.erb
<%= render 'form', book: @book %><%= render 'index', books: @books%>

以上になります。

Discussion