【Rails+jQuery Raty】レビュー用の星★の評価を実装する(入力、保存、表示)

絶賛、プロテインの口コミ共有サービスを開発しております。

・SuppleBox（サプリボックス）：https://supplebox.tokyo

その中で、Amazonなどに見られる「★による評価機能」がカッコ良いなと思ったので実装していきます。

# 環境

- 言語(Ruby 2.5.3)
- フレームワーク(Rails 5.2.3)
- 開発(Cloud9)

# 実現したいこと
 1.星★による評価の入力と保存
まずは、newやeditページで★による入力と保存を行います

 2.星★による評価の表示
次に、newやeditページで入力・保存した★による評価の値をshowページやindexページで表示します。

# 前提

- postsテーブル(口コミ投稿用のテーブル)のrateカラム（型:float）に評価値を保存する

すでに、テーブルとカラムは作成されていることを前提に進めます。

カラムは、半分の星による評価を行う場合、「0.5」や「1.5」という値を保存することになるため、`float`型にしておく必要があります。

もし、`integer`や`string`の型として作成してしまっていた場合は、データベースによって変更方法は異なりますが、型の変更が必要になります。

# 参考

[jQuery Raty](http://itref.fc2web.com/javascript/jquery/raty.html)
[Railsで星の評価を機能をつける](https://qiita.com/kitaokeita/items/1e40724c3384507cec13)
[jQuery Ratyの使い方](https://github.com/wbotelhos/raty)

# javascriptの読み込み、★画像の読み込み

上記参考リンクを確認しながら、javascriptの読み込みと★画像の読み込みを行います。


# 星による評価の入力、保存

実装後イメージは下記。

<img width="960" alt="スクリーンショット 2019-05-25 21.35.06.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331354/7de7d7fe-ec8a-5f65-408b-71f21b3498ce.jpeg">

```erb

<!-- 口コミ入力フォーム -->
<%= form_for post do |f| %>

  <!--エラーメッセージ-->
  <%= render 'layouts/error_messages', model: f.object %>
  
  <!--商品コードの送信-->
  <%= f.hidden_field :product_id, { value: product.id} %>
  
  <!-- タイトル -->
  <div class="form-group row">
    <%= f.label :title, 'タイトル ', class:'col-md-3 col-form-label' %>
    <div class="col-md-9">
      <%= f.text_field :title, class: "form-control" %>
    </div>
  </div>
  
  <!-- 評価 -->
  <div class="form-group row" id="star">
    <%= f.label :rate,'評価 ', class:'col-md-3 col-form-label' %>
    <%= f.hidden_field :rate, id: :review_star %>
  </div>

  <!-- 評価javascript -->
  <script>
  $('#star').raty({
    size     : 36,
    starOff:  '<%= asset_path('star-off.png') %>',
    starOn : '<%= asset_path('star-on.png') %>',
    starHalf: '<%= asset_path('star-half.png') %>',
    scoreName: 'post[rate]',
    half: true,
  });
  </script>  

  <!-- 口コミ -->
  <div class="form-group row">
    <%= f.label :content, '口コミ内容 ', class:'col-md-3 col-form-label' %>
    <div class="col-md-9">
      <%= f.text_area :content, class: "form-control", rows: "8",
        placeholder:'口コミ内容がなくても、タイトルと評価のみで投稿できます。
まずは投稿してみましょう！投稿してから編集もできますよ！' %>
    </div>
  </div>
  
  <!-- 確認ボタン -->
  <div class="form-group row justify-content-end">
    <div class="col-md-9">
      <%= f.submit '投稿する', class:"btn btn-success" %>
    </div>
  </div>
 
<% end %>
<!-- /口コミ入力フォーム -->

```

ポイントは下記。

```erb
# Postモデルのrateカラムに値を保存する
scoreName: 'post[rate]',
```

```erb
# ★の半分の入力を行う
half: true,
```

# 星による評価の表示

実装後イメージは下記。口コミ投稿一覧にて、★を表示したい。
上記の「★の入力、保存」と異なる点は、`1.入力はせず表示する` 、 `2.繰り返し処理をする`ということになります。

<img width="972" alt="スクリーンショット 2019-05-25 21.43.34.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331354/513eff10-e40c-7a5d-eb64-6a01f4461791.jpeg">


```erb
<% if posts.present? %>
  <% posts.each do |post| %>
    <div class="row posts">
      <div class="col-md-2 posts-user">
        <%= link_to post.user do %>
        <%= image_tag post.user.picture.url ,width: '100px' %>
        <% end %>
        <p class="posts-title"><%= link_to post.user.name, post.user %></p>
        <p class="posts-prof"><%= post.user.gender %> <%= post.user.height %> <%= post.user.weight %></p>
      </div>
      <div class="col-md-6 mb-3">
        <div class=" posts-content">
          <p><%= simple_time(post.created_at) %></p>
          <h4 class="mb-3">評価：<%= post.rate %>点 | <%= post.title %></h4>

          <!--星評価-->
         <div id="star-rate-<%= post.id %>"></div>
          <script>
          $('#star-rate-<%= post.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: <%= post.rate %>,
          });
          </script>  
        <!--/星評価-->

          <p><%= post.content %></p>
          <%= image_tag post.picture.url, class:'img-fluid' if post.picture? %>
        </div>
      </div>
      <div class="col-md-4">
        <%= link_to post.product do %>
          <div class="posts-product">
            <img src="<%= post.product.image_url %>" alt="">
            <p><%=  post.product.title %></p>
          </div>
        <%end %>
      </div>
      <div class="col-md-12 edit-button">
        <% if current_user == post.user %>
          <%= link_to '口コミを編集', edit_post_path(post), method: :get, class:'btn btn-default' %>
          <%= link_to '口コミを削除', post, method: :delete, class:'btn btn-default' %>
        <% end %>
      </div>
    </div>
  <% end %>
<% end %>

```

ポイントは下記。

```erb
# 繰り返し処理を実行してもidを一意に保てるようにpost.idを埋め込む
<div id="star-rate-<%= post.id %>"></div>
```

```erb
# 読み取り専用（入力できない）
readOnly: true,
# 星の入力値を読み込む
score: <%= post.rate %>,
```

# 豆知識
JavaScriptがうまく機能しないときは、 デベロッパーツール を見るのが重要なのですね。

どのように表示されているか確認し、デバッグしながら進めることでなんとか実装できました。

# まとめ
JavaScriptを触ったのはほぼ初めてでしたが、サービスに動きをつけられてとても感動しました。

Railsの勉強が落ち着いたら、しっかり勉強したいなと感じた所存。