🎃

Rails|jQuery Ratyを利用して、投稿に星評価を作成

2023/08/07に公開

要件

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

開発環境

ruby 3.1.2p20
Rails 6.1.7.4
Cloud9

前提

jQueryを導入済み
Bookモデルを作成済み

jQuery Raty をインストールする

インストール方法はこちらの記事の通り。
Ratyのインストール、画像ファイルの移動、jsファイルへの書き込みまで行う。
https://zenn.dev/airiin/articles/c4eabd8d91daa6

Bookモデルに starカラムを追加

Bookモデルに星評価のデータを保存するための starカラムを追加する。

$ rails g migration AddStarToBook star:string
$ rails db:migrate

Booksコントローラの編集

Booksコントローラの book_paramsを編集し、starカラムが保存できるようにする。

books_controller.rb
  def book_params
    params.require(:book).permit(:title, :body, :star)
  end

books/new と books/edit ビューの作成

books/_form.html.erb
<%= form_with model:book,local:true do |f| %>
  <div class="form-group">
    <%= f.label :title %>
    <%= f.text_field :title, class: 'form-control book_title' %>
  </div>

  <div class="form-group">
    <%= f.label :opinion %>
    <%= f.text_area :body, class: 'form-control book_body' %>
  </div>

  <% 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 "books/static_rate", book: book %>
      </div>
    <% end %>

  <div class="form-group">
    <%= f.submit class: 'btn btn-success' %>
  </div>
<% end %>

Bookの新規作成画面と、Bookの編集画面でレンダリングしている books/_form.html.erb を上記のように編集します。

<div id="post_raty"></div>
この部分に星評価の画像が表示されます。

<script>〜</script>
この部分に JavaScriptコードを記述できます。

$(document).on('turbolinks:load', function() {
この部分は、以降の JavaScriptコードを実行するためのものです。

let elem = document.querySelector('#post_raty');
if(elem == null) return;
この部分で、#post_raty というidを持つ要素を取得し、elemに代入しています。
もしその要素がなければ、何もせずに関数を終了します。

elem.innerHTML = ""
次に、#post_raty というidを持つ要素がある場合についてです。
その要素の中身を空にしています。

let opt = { starOn: "<%= asset_path('star-on.png') %>", starOff: "<%= asset_path('star-off.png') %>", starHalf: "<%= asset_path('star-half.png') %>", scoreName: 'book[star]', };
この部分で、Ratyの細かい設定をしています。
starOn/Off/Halで、星を表示する際の画像のパスを指定しています。
scoreNameで、スコアの値(星の数)が格納されるフォーム要素の名前を指定しています。
これらの設定を optに代入します。

raty(elem, opt);
raty関数を呼び出して、星評価の表示を #post_raty 部分に適用します。ratyはjQuery Ratyライブラリが提供する関数で、引数にHTML要素と設定オブジェクトを取ります。

books/new.html.erb
<%= render "books/static_rate", book: @book %>
books/edit.html.erb
<%= render "books/static_rate", book: @book %>

追記
edit画面では、すでに投稿済みのレビューから、星評価の値を取得したいので、
オプション部分に
score: <%= @review.star_integer %>
を追記する必要がある。

ビューの例

let opt = {
                    starOn: "<%= asset_path('star-on.png') %>",
                    starOff: "<%= asset_path('star-off.png') %>",
                    starHalf: "<%= asset_path('star-half.png') %>",
                    scoreName: 'review[star_integer]',
                    score: <%= @review.star_integer %>
                  };

books/show と books/index ビューの作成

books/show と books/index では、星評価の結果を表示します。
これら両方にレンダリングされている books/_static_rateビューを作成します。

books/_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,
        };
        raty(elem, opt);
      });
</script>

<div id="star_<%= book.id %>"></div>
星評価の画像が表示される部分です。bookデータによって表示が変わるので、idに @book.idを入れています。

readOnly: true,
この星評価の表示部分が、読み取り専用であることを示しています。編集することはできません。

他の部分は先のコードと同じです。

books/show.html.erb
<%= render "books/static_rate", book: @book %>
books/_index.html.erb
<%= render "books/static_rate", book: book %>

以上で完成です!

https://zenn.dev/goldsaya/articles/2746dd2b886be0

Discussion