LoginSignup
41
48

More than 3 years have passed since last update.

Railsで「Raty」を使った星機能をつける

Last updated at Posted at 2020-01-06

コンビニで気軽に採れる高タンパク質を管理するサイトを作成時
ユーザーが口コミ投稿できる機能を作成、星による評価機能があるといいなと思ったので実装。
似たような記事は他にもあるが、slimで書かれている記事がなかったので執筆。

対象者、環境

・Railsで「Raty」を使って星の機能を作成したい人
・slimを使用している
・Rails 5.2.4

ゴール

・星の入力(0.5単位)
・星の表示
・平均点算出

参考URL

イメージ

Image from Gyazo

前提

・Userモデル
・Foodモデル
・Reviewモデル

があることを前提にすすめます。テーブル相関図
今回は、「rate」以外が全てあると思ってください

FoodやReviewはご自身のモデルとあてはめてくださいm(_ _)m

入力編 formで表示しよう

カラム追加

be rails g migration AddRateToReview rate:float

class AddRateToReview < ActiveRecord::Migration[5.2]
  def change
    add_column :reviews, :rate, :float, null: false, default: 0
    # floatにすることを推奨(小数点に対応できるため)。nullの制約は各自判断してください
  end
end

モデル側は下記。1以上~5以下の数字はお好みで。

review.rb

  validates :rate, numericality: {
    less_than_or_equal_to: 5,
    greater_than_or_equal_to: 1
  }, presence: true

画像を外部から保存する

こちらのGithubから画像をassets/images配下に保存します。

Image from Gyazo

jsのコードをコピーする

こちらのGithubからコードをコピーして、jquery_raty.js等の適宜名前を振り、
applicaiton.jsから requireしてあげる

viewに追加

ストロングパラメータに追加等した後、(i18n化もしてます)

#star.form-group
   = f.label :rate
   = f.hidden_field :rate, id: :review_star
  #star がポイントです(jsを呼ぶ)

同じviewファイル内に、

javascript:
 $('#star').raty({
   size: 36,
   starOff: "#{asset_path('star-off.png')}",
   starOn: "#{asset_path('star-on.png')}",
   starHalf: "#{asset_path('star-half.png')}",
   scoreName: 'review[rate]', # reviewカラムに保存するので忘れないように
   half: true, # ★の半分の入力を行う
 });
# ダブルクオーテーションで囲みましょう

ここまで入力すれば、下記のように表示がされているはず。実際に保存できているか、DBを確認するのも忘れずに!
もし表示出来ていなければ、デバックして確認しましょう。
Image from Gyazo

表示編 eachで回そう

次は、DBに保存された数字をviewに描写します。

_review.html.slimで回す

eachで回すことを前提に話を進行します。


id="star-rate-#{review.id}"

の様に書くことで、idを動的に出来ます。

表示編 平均点を出そう

最後におまけで、reviewの平均点を出したいと思います。

reviewは、foodモデルに紐付いており、食品がレビューを複数持つという関係性です。(詳しくは最初の参考資料を御覧ください)

紐付いたものをaverage等でいい感じにしてあげると,こんな感じで表示ができるはず!

_food.html.slim
.col-md-3.col-sm-4.col-xs-12.text-center#food_parts
  food[id="#{food.id}"]
  = link_to image_tag(food.decorate.image_url, width: 220, height: 220, class: 'food_parts_image'),food_path(food)
  .card-body
    h5
      = link_to food.name, food_path(food)
    ul.text-left
      li 税込#{food.price}li #{food.protein}g
      li #{food.brand.pluck(:name).first}
      li id="star-rate-#{food.id}" 口コミ#{food.reviews.count} &nbsp;
//注目ポイント ↑
    == render 'likes/likes_basic', food: food #いいね機能です、無視してください
//星評価
javascript:
  $('#star-rate-#{food.id}').raty({
    size: 36,
    starOff: "#{asset_path('star-off.png')}",
    starOn: "#{asset_path('star-on.png')}",
    starHalf: "#{asset_path('star-half.png')}",
    half: true,
    readOnly: true,
    score: "#{food.reviews.average(:rate).to_f.round(1)}",
    //注目ポイント↑ 平均点を算出し、round関数で切り上げ
  });
//星評価終わり

こんな感じで表示ができるはず!(ちなみに、おすすめのサラダチキンはファミマです)
(画像の星では、口コミ2件で 「4」と「2」の評価がついています。
Image from Gyazo

汚くなったコードはパーシャルで

現状のviewはjsがべた書きになっていると思います。
shared/_starなどを作って、jsだけパーシャルにしましょう!レッツリファクタ!😉

_star.html.slim
/ 星評価 review_formからrender(newとeditで使用中)
javascript:
  $('#star').raty({
    size: 36,
    starOff: "#{asset_path('star-off.png')}",
    starOn: "#{asset_path('star-on.png')}",
    starHalf: "#{asset_path('star-half.png')}",
    scoreName: 'review[rate]',
    half: true,
  });

/ 星平均 _foodからrender
- if food.present? #自分の仕様上必要なif文
  javascript:
    $('#star-rate-#{food.id}').raty({
      size: 36,
      starOff: "#{asset_path('star-off.png')}",
      starOn: "#{asset_path('star-on.png')}",
      starHalf: "#{asset_path('star-half.png')}",
      half: true,
      readOnly: true,
      score: "#{food.reviews.average(:rate).to_f.round(1)}",
      // 平均点を算出し、round関数で切り上げ
    });

これでだいぶすっきりしたと思います。

まとめ

実装初期、jsファイルに必死に'#{asset_path('star-off.png)}',のようにasset_pathを書いていましたが、呼び込まれずハマりました。

冷静に考えると、jsとRubyで生成されるタイミングが違うので、jsファイルにasset_pathを書いても動きませんよね(という認識です)。gon というgemを使えばなんとかなる、、らしいのですが、試してはいません。

gonを使ったRailsとJavascriptの連携について

星機能を実装するには、ratyやrate.yoなどがありますが、分かれば比較的簡単なratyはおすすめです。
星、テンション上がりますね😊

41
48
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
48