Rails|jQuery Ratyを利用して、投稿に星評価を作成
要件
ユーザ自身の投稿にのみ、5 段階評価をつけられる。
評価をつけられるタイミングは、投稿時に限定
本の一覧ページと詳細ページに 5 段階評価を表示させる
ユーザーの詳細ページに 5 段階評価を表示させる
一度評価をつけたら変えられない
開発環境
ruby 3.1.2p20
Rails 6.1.7.4
Cloud9
前提
jQueryを導入済み
Bookモデルを作成済み
jQuery Raty をインストールする
インストール方法はこちらの記事の通り。
Ratyのインストール、画像ファイルの移動、jsファイルへの書き込みまで行う。
Bookモデルに starカラムを追加
Bookモデルに星評価のデータを保存するための starカラムを追加する。
$ rails g migration AddStarToBook star:string
$ rails db:migrate
Booksコントローラの編集
Booksコントローラの book_paramsを編集し、starカラムが保存できるようにする。
def book_params
params.require(:book).permit(:title, :body, :star)
end
books/new と books/edit ビューの作成
<%= 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要素と設定オブジェクトを取ります。
<%= render "books/static_rate", book: @book %>
<%= 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
ビューを作成します。
<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,
この星評価の表示部分が、読み取り専用であることを示しています。編集することはできません。
他の部分は先のコードと同じです。
<%= render "books/static_rate", book: @book %>
<%= render "books/static_rate", book: book %>
以上で完成です!
Discussion