【Rails6】レビューの平均値をレーダーチャートで表示する方法（gon、chartkick、chart.js）

# 概要
* Userが５段階評価ができる5つの項目のレビューを行うと、それぞれの平均値がレーダーチャートとなってトップビューに表示される実装を行ったので、その手順を記す。５段階評価機能については、別記事でまとめています。
    * [【Rails6】5段階評価の星レビュー機能を実装する手順（raty.js）](https://qiita.com/Ryo-0131/items/63e81b13b9382690bee4)

# 前提
* 今回の実装においては、chart.jsとchartkick両方を利用する。利用先は以下の通り。
    * トップビュー（/index）：chartkickでバーチャート表示
    * 詳細ページ（/show）:chart.jsでレーダーチャート表示
* JSとrailsの連携は、gem gonを利用する。（chartkickはrails内で完結）
    * gonとは：controller内でセットした変数をJavascript内で使う事ができるgem。他にもあると思いますが、今回はこちら使用
* テーブルやカラムの関係性については、下記データベース設計を参照。

# データベース設計
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/a1556142-281f-e46d-b3ad-ebad79ad6aab.png)

# gonとchartkick、chart.jsのインストール

* Gemfileに以下を追記して、bundle installを行う
    * 上述の通り、JavaScriptとの連携が必要なので、gonというgemを利用してデータ渡しを行う。

```ruby
gem 'gon'
gem 'chartkick'
```
* `yarn add chartkick chart.js`を行ってインストール
* `application.js`で`chart.js`と`chartkick`を追加
```app/javascript/packs/application.js 
require("chartkick")
require("chart.js")
```

* `application.html`に以下記載。CDNに公開されているjsファイルを読み込む。
    * gonもここで設定するので、`include_gon`を記載しておく
```app/views/layouts/application.html.erb
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js"></script>

<%= include_gon %>
```


# chartkickについて
* 簡単にグラフを作成することができるグラフ描画ライブラリ。他の言語でも使えるが、主にRubyで使われることが多いらしい。
* 今回の場合...
    * index時では個別idが振られておらず、＠reviewにおけるrailsとjavaの連携が難しいため（gon利用してもできず）、railsで完結するchartkickを利用。これにより、indexページの時点で各種項目の表示が可能になる。


# トップビュー(/index)にchartkickでバーチャートを表示する
* itemコントローラーには以下が記載済み
```app/controllers/items_controller.rb 
class ItemsController < ApplicationController
  def index
    @items = Item.all.page(params[:page]).per(10).order(item_name: 'ASC')
    @itemsindex = Item.all.order(item_name: 'ASC')
    @reviews = Review.all
    @all_rating = '総合評価'
    @rating1 = '評価1'
    @rating2 = '評価2'
    @rating3 = '評価3'
    @rating4 = '評価4'
    @itemname =  Item.pluck(:item_name)
    gon.itemname = @itemname
  end
```

* `_item.html.erb`に以下を追記する
    * 部分テンプレート作っていなければ`index.html`。今回はindexで`<%= render partial: 'item', collection: @items %>`をしているので、`_item.html.erb`に記載しています

```erb:app/views/items/_item.html.erb
<%= column_chart  [
     ["評価1", item.reviews.average(:rating1).to_f.round(1)],
     ["評価2", item.reviews.average(:rating2).to_f.round(1)],
     ["評価3", item.reviews.average(:rating3).to_f.round(1)],
     ["評価4", item.reviews.average(:rating4).to_f.round(1)],
      ] , label: "#{item.item_name}の評価" , width: "300px", height: "300px" , min: 0, max: 5, 
     colors: ["#FF0000", "#FFA500", "#AFDFE4", "#F0FFF0"] 
     %>
```

* グラフの種類は以下がある
    * column_chart(縦棒グラフ)
    * bar_chart(横棒グラフ)
    * line_chart(折れ線グラフ)

# chartkickで解決できなかった問題
* いくつか不具合？が発生。どこかのgemが影響しているのか？対応方法不明。
    * bar_chartと記載しても、column_chartになってしまう
    * Min/Maxを設定しているのに反映されない
    * ラベルを消しても、赤い四角だけが残る。
* 以下で2022/06/11に質問したが、回答なし...
    * [Chartkick.jsで、最大値・最小値が正しく設定されない](https://teratail.com/questions/2glnd5cocyo7xm)
    * もし同じような現象になって、解決できた方がいたら教えてください!

# 詳細ページ(/show)にchart.jsでレーダーチャートを表示する
* itemコントローラーで以下を記載する
    * 上述の通り、JavaScriptとの連携が必要なので、gonというgemを利用してデータ渡しを行う。
```app/controllers/items_controller.rb 
  def show
    @item = Item.find(params[:id])
    @review = Review.new
    @reviews = @item.reviews.includes(:user)
    gon.item = @item
    gon.rate1 = @item.reviews.average(:rating1).to_f.round(1)
    gon.rate2 = @item.reviews.average(:rating2).to_f.round(1)
    gon.rate3 = @item.reviews.average(:rating3).to_f.round(1)
    gon.rate4 = @item.reviews.average(:rating4).to_f.round(1)

    @all_rating = '総合評価'
    @rating1 = '評価1'
    @rating2 = '評価2'
    @rating3 = '評価3'
    @rating4 = '評価4'
  end
```

* `_show_chart.html.erb`に以下を追記する
    * 部分テンプレート作っていなければ`show.html`。今回はindexで`<%= render partial: "items/show_chart" %>`をしているので、`_show_chart.html.erb`に記載しています

* `chart.js`はグラフ描画エリアの指定に、canvas要素を使用する
    * `<canvas id="myChart"></canvas>　`
* canvas要素（ID ： myChart ） を取得し、変数 ctx に入力する
    * `var ctx = document.getElementById("myChart");`
* 今回はレーダーチャートなのでradarを選択
    * `type: 'radar'`。他にも公式サイトにたくさん種類あります
* dataには、controllerで定義した以下を代入
    * `data: [gon.rate1, gon.rate2, gon.rate3, gon.rate4]`
    * ※総合評価はレーダーチャート項目には含めていません
* labelには、controllerで定義した以下を代入。
    * `label:  gon.item.item_name`
* optionで、最小値・最大値を設定。

```erb:_show_chart.html.erb
<div class="chartbox">
<canvas id="myChart"></canvas>　
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
  type: 'radar',
  data: {
    labels: ["評価1", "評価2", "評価3", "評価4"],
    datasets: 
    [
        {
        label:  gon.item.item_name ,
        backgroundColor: 'rgba(255,140,0,0.2)',
        borderColor: 'rgba(255,69,0,0.2)',
        data: [gon.rate1, gon.rate2, gon.rate3, gon.rate4]
        },
    ]
  },
  options: {
      scale: {
          ticks: {
              suggestedMin: 0,
              suggestedMax: 5
          }
      }      
  }
});
   
</script> 
</div>
```