Rails 星5レビュー機能
5段階評価をつける
要件
- ユーザ自身の投稿にのみ、5 段階評価をつけられる。
- 評価をつけられるタイミングは、投稿時に限定
- 本の一覧ページと詳細ページに 5 段階評価を表示させる
- ユーザーの詳細ページに 5 段階評価を表示させる
- 一度評価をつけたら変えられない
完成
5段階評価の実装方法
5段階評価の実装方法は様々な手法があるが、今回はRatyを使用する!
Ratyは、JavaScriptで作成されたプラグインで、レーティング(格付け)を星型のアイコンで表示及び入力できる⭐️
〜事前準備〜
jQueryのインストール
yarn add jquery
webpackerの設定ファイルで、jQueryを管理下に追加するための記述を追加。
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を呼び出す。
省略
#追記
window.$ = window.jQuery = require('jquery');
raty.jsの導入
githubよりダウンロード
⇩
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に下記を追加
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カラムを追記する!
:
private
def book_params
params.require(:book).permit(:title, :body, :image, :star)#ここのstar
end
end
permitメソッドへ追記することで'star'が保存できるようになる!
viewの記述
indexとeditで使用される部分テンプレート
# 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 で使用される部分テンプレート
<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プラグインをインスタンス化する。これにより、ユーザーがそのブックにつけた評価が表示される。
必要な箇所に部分テンプレートを呼び出し
<%= render "books/static_rate", book: book %>
<%= render 'form', book: Book.new %>
:
<%= render "static_rate", book: @book %>
<%= render 'form', book: @book %>
<%= render 'form', book: @book %>
:
<%= render 'index', books: @books %>
🌱参考にさせていただいたサイト
過去の部分テンプレートとか、おかしい記述なおしながらやったら
めちゃくちゃ時間かかってしまってもうこんな時間に、、
まだ詳しいとこまとめきれてないので明日再度まとめます🏋🏻
Discussion