🙆

[Rails/JS] raty.jsで星reviewをつける

2023/02/10に公開

今回作成するもの

JQueryの記述方法ではなく、バニラなJSの記述を使用して実装していきます。

作成方法

jQueryのインストール

以前に既に Gem Fileに  gem 'jquery-rails' でbundle installしてます。

ratyをgithubからダウンロード(clone)する。

< clone 方法>
https://github.com/wbotelhos/raty
これを一旦ダウンロードします。このページで以下のようにHTTPsをコピー。

ターミナルで、 git clone RatyのHTTP

これでダウンロードされました。

画像をそのratyからコピー、自分のapp/assets/imagesに配置

Raty>src>の中にimgsあるので、それをコピーしてapp/assets/imagesに入れる。

同様に、src/raty.jsを自分のapp/javascriptにコピー

星保存用のカラムを追加する

Bookモデルに、starカラムの追加を行う。
$ rails g migration AddStarToBooks star:float

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

app/javascript/packs/application.jsに下記を追加

window.raty = function(elem, opt) {
let raty = new Raty(elem, opt)
  raty.init(); // initialize (初期化)
  return raty;
}

ここでの記述を少し説明すると…

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

  • <** Object.keys() メソッド**>
    オブジェクトのプロパティを取得するために使うもの.

  • <function>
    function(関数)とは、様々な処理を1つにまとめて、名前をつけることができるもの

ここから以下の記事全てに共通する内容だが、letで宣言してるからそこで一回しか使えないので注意。

JSの変数はここにまとめてあるよ!
https://zenn.dev/airiswim/articles/86ac832d0ad994

books_controllerのparamsにstarカラム追記

:
private

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

view(html)の記述を行なっていく

まずはBook create時の ratyから。

<_form.html.erb>

//評価表示部位
<div id="stars">
<label>Rate</label>
</div>

<script>
  let elem = document.querySelector('#stars');
  let opt = {
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    starHalf: "<%= asset_path('star-half.png') %>",
    scoreName: 'book[star]' 
  };
  window.raty(elem, opt);
</script>

評価の★マークを表示する場所に<div id="stars"> </div>のようにidを作成する。

<script></script>で囲った部分はjsの記述。
https://github.com/wbotelhos/raty

ここのratyのReadMeのoptionを見るとわかりやすい。
scoreName: 'book[star]'  ここで、保存するモデル名[カラム名]の記述。
この中にRubyの記述を行なっていく際は、””で囲うことで使用できる。

作成後に、Bookshow(本詳細ページ)で星数の表示をしたい

ここでも記述方式はほぼ同じだが、
idと、letで宣言した変数の二つは使用できるのが一回限りなので、名前を変えましょう。

<div id="show-stars"></div>
	
:
<script>
  let showRateElement = document.querySelector('#show-stars');
  let showOpt = {
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    starHalf: "<%= asset_path('star-half.png') %>",
    scoreName: 'book[star]',
    score: "<%= @book.star %>",
    readOnly: true
  };
  window.raty(showRateElement, showOpt);
</script>	

ここでは、book-createした時の評価(score)を持ってくる必要があるので、
score: "<%= @book.star %>"
これで持ってくる。そして、詳細表示ページであって、投稿する時のように、星の数を変更できては困るので、
readOnly: true の記述です。

星の数をeditページでも表示したい!

ここでの問題は、formをpartialにしているという点だ。
作成時も、編集時も、同じものなのだ。
編集ページではその本で元来評価されたものを一旦そのまま持ってきたいし、
作成ページでは0のところから、自由につけたい。

Viewページで条件分岐します。
 
一番最初に作成したform部分の
<script></script>部分を以下のように変更します。
<_form.html.erb>

:
:
<script>
  let elem = document.querySelector('#stars');
  let opt = {
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    starHalf: "<%= asset_path('star-half.png') %>",
    scoreName: 'book[star]',
    score: "<%= isEdit ? jonsoku.star : 0 %>"
  };
  window.raty(elem, opt);
</script>

score: "<%= isEdit ? jonsoku.star : 0 %>"ここの記述に注目したい。

これは、If else文を1行表記にしたものだ。

<基本型>	
条件式 ? 「真(true)」となった場合に実行したい処理 : 「偽(false)」となった場合に実行したい処理

isEdit ? そうなら変数に入っている星の数を。:  違うなら0を 
という意味になる。

この isEdit を今度はtrue/falseでrender文で表記していく。

このように、右のeditページでのrenderは、true表記

<%= render partial: 'books/form', locals: { jonsoku: @book, btn: @btn, isEdit: true } %>

その他のページでのrenderは、false表記で区別する。

 <%= render partial: 'books/form', locals: { jonsoku: @newBook, btn:@btn, isEdit: false } %>

これで完成!以上!

Discussion