🌩️

Rails 星5レビュー機能

2023/05/06に公開

5段階評価をつける

要件

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

完成

5段階評価の実装方法

5段階評価の実装方法は様々な手法があるが、今回はRatyを使用する!

Ratyは、JavaScriptで作成されたプラグインで、レーティング(格付け)を星型のアイコンで表示及び入力できる⭐️

〜事前準備〜

jQueryのインストール

yarn add jquery

webpackerの設定ファイルで、jQueryを管理下に追加するための記述を追加。

config/webpack/environment.js
const { environment } = require('@rails/webpacker')
#追記
const webpack = require('webpack')

environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    jquery: 'jquery/src/jquery',
  })
)
#ここまで
module.exports = environment

最後に、jQueryを呼び出す。

app/javascript/packs/application.js
省略

#追記
window.$ = window.jQuery = require('jquery');

raty.jsの導入

githubよりダウンロード

https://github.com/wbotelhos/raty


SSHをコピーして、ターミナルでgit cloneを行う。

画像を app/assets/imagesに配置

raty/src/imagesの中にある下記3つのスターの画像を自分のapp/assets/imagesフォルダに格納

star-half.png
star-on.png
star-off.png

src/raty.jsをapp/javascriptにコピー

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つにまとめて、どこからでも使えるように効率化するという目的でよく使われている。

投稿フォームに星レビュー機能の追加

1. "star"カラムの追加

rails g migration AddStarToBooks star:string

これでbooksテーブルにstring型のstarカラムの追加用マイグレーションファイルが作成される!

半分の星(0.5や1.5という値を保存する)による評価を行う場合は float型
整数でのみの評価ならカラムはinteger型

rails db:migrate

2."star"カラムを保存できるようにデータ操作を許可する。

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

controllers/books_controller.rb
:
private

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

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

viewの記述

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

books/_form.html.erb
# new book投稿フォーム
<%= 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>
  
  # starについての記述
  <% 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 %>
  
  <div class="form-group">
    <%= f.submit class: 'btn btn-success' %>
  </div>
<% end %>

~解説~
新しい書籍を作成するときには、評価の星の評価を追加するためにRatyプラグインが使用され、既存の書籍の場合、_static_rateファイルが使用される。

新しい書籍の場合、フォームの star フィールドには hidden_field が設定される。
評価の星の評価を受ける場所には post_raty という名前の要素があり、JavaScriptでRatyプラグインが初期化される。フォームの scoreName フィールドが book[star] に設定されるため、これはフォーム送信時に評価される。

既存の書籍の場合、 下記の_static_rate ファイルが使用される。このファイルは、 show.html.erb で使用される部分テンプレート。_static_rate ファイルは、既存の書籍の評価を表示するために使用され、読み取り専用になっている。_static_rate ファイルでは、Ratyプラグインが使用されているが、readOnly パラメータが設定されているため、ユーザーは評価を変更できない!!

show.html.erb で使用される部分テンプレート

_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>

~解説~
ブックの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 %>

🌱参考にさせていただいたサイト

https://qiita.com/kcl215/items/e226ac58d14360fd1b8e
https://zenn.dev/airiswim/articles/31b29cd23e011d

過去の部分テンプレートとか、おかしい記述なおしながらやったら
めちゃくちゃ時間かかってしまってもうこんな時間に、、

まだ詳しいとこまとめきれてないので明日再度まとめます🏋🏻

Discussion