【Rails】コメント機能に星評価機能を導入する

#はじめに
Raty.jsというものを使い、コメント形式で投稿を星評価できるようにします。
また、多数のユーザーからの星評価の平均を出力することもできたので、そちらも合わせて紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1363783/6e3c2dd1-e677-ccee-6bad-8d5d83bbd794.png)

#使用環境
Ruby on Rails 6
#前提
・CRUD機能を実装している事
・deviseを導入している事
・コメント機能を実装している事
#モデルの設計
・Userモデル(deviseで作成)
・Tweetモデル
・Commentモデル
#Commentモデルにrateカラムを設置
```java:ターミナル/コマンドプロンプト
rails g migration AddRateToComments rate:float
```
Raty.jsを用いる際にはrateカラムが大切になってきます。今回は「星1.5」などにも対応するため、float型を用いています。
#Commentモデルにバリデーションを追加
```java:app/models/comment.rb
validates :rate, numericality: {
    less_than_or_equal_to: 5,
    greater_than_or_equal_to: 1}, presence: true
```
ここでは、星が1~5までで保存できるようになっています。
#表示するために星の画像を追加
https://github.com/wbotelhos/raty/tree/master/lib/images
ここから星の画像をダウンロードできます！ダウンロードした画像は、「app/assetes/images」直下に保存します。
#jQueryの導入
```java:ターミナル/コマンドプロンプト
yarn add jquery
```
yarn addコマンドは、パッケージのインストールと共に、package.jsonへバージョンを書き込んでくれます。

次に、webpackerの設定ファイルで、jQueryを管理下に追加するための記述をします。

```java:config/webpack/environment.js
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を呼び出します。

```java:app/javascript/packs/application.js
省略

window.$ = window.jQuery = require('jquery');　追記
```
#Raty.jsの導入
app/javascript/packsにraty.jsというファイルを作成します。

次に下記URLのjsコードをraty.jsにコピーする。
https://github.com/wbotelhos/raty/blob/master/lib/jquery.raty.js

最後にapplication.js に下記を追加します。

```java:app/javascript/packs/application.js
window.$ = window.jQuery = require('jquery'); 
require('packs/raty') 追記
```
#Controller設計
```java:app/controllers/tweets_controller
省略

def show
     @tweet = Tweet.find(params[:id])
     @comments = @tweet.comments
     @comment = Comment.new
end

省略
```

```java:app/controllers/comments_controller
def create
     tweet = Tweet.find(params[:tweet_id])
     comment = tweet.comments.build(comment_params) #buildを使い、contentとtweet_idの二つを同時に代入
     comment.user_id = current_user.id
     if comment.save
         flash[:success] = "コメントしました"
         redirect_back(fallback_location: root_path)
     else
         flash[:success] = "コメントできませんでした"
         redirect_back(fallback_location: root_path)
     end
 end

 private
 def comment_params
     params.require(:comment).permit(:content, :rate)
 end
```
#View設計
```java:app/views/tweets/_rate_average.html.erb
<div class="average-review-rating" data-score=<%= @comments.average(:rate) %>></div>

<script>
  $('.average-review-rating').raty({
    readOnly: true,
    starOn: "<%= asset_path('star-on.png') %>",
    starOff: "<%= asset_path('star-off.png') %>",
    starHalf: "<%= asset_path('star-half.png') %>",
    score: function() {
      return $(this).attr('data-score')
    }
  });
</script>
```

```java:app/views/tweets/show.html.erb
<%= render 'rate_average' %>
<div class="comment-container">
  <% @comments.each do |c| %>
    <div class="pt-2 px-2" style="background-color: #fffffe; border: 2px solid #272343; border-radius: 2px;">
        <div class="review-rating" data-score="<%= c.rate %>">評価：<%= c.rate %></div>
        
        <div class="text-left">
            <p>投稿者：<%= c.user_id %></p>
            <p><%= c.content %></p>
        </div>

        <div class="text-right">
            <p>
                投稿日：<%= c.created_at.strftime('%Y/%m/%d') %>
            </p>
        </div>
    </div>

    <div class="pb-2"></div>

  <% end %>

  <%= form_with(model: [@tweet, @comment], local: true) do |f| %>

    <%= f.text_area :content, rows:'5', placeholder: "コメント", class: "form-control form-control-sm" %>
    <div id="rating-form">
        <label>評価：</label>
        <%= f.hidden_field :rate, :value => 'score' %>
    </div>

    <%= f.submit "投稿する" %>
  <% end %>
</div>

<script>
    $('#rating-form').raty({
        starOn: "<%= asset_path('star-on.png') %>",
        starOff: "<%= asset_path('star-off.png') %>",
        scoreName: 'comment[rate]'
    });
</script>
```
#参考記事
https://nllllll.com/ruby-on-rails/rails-raty-js-review/
https://qiita.com/nozomi_nozomi/items/eb6848c6025ca63af1c4