69101
# 解決したいこと

Chart.js上で表示される値が、実際にDBに格納されているラベル・値共に対応していないため、正しいラベル・値を表示させたい

### イメージ

[![画像の説明をここに入力](https://i.stack.imgur.com/bZHg6.png)](https://i.stack.imgur.com/bZHg6.png)

[![画像の説明をここに入力](https://i.stack.imgur.com/qibiK.png)](https://i.stack.imgur.com/qibiK.png)

# 環境

・Ruby：2.6.5  
・Rails:5.2.4.3  
・DB：PostgreSQL

# 試したこと

logger.infoでどんな値が格納されたのか確認したのですが、Controllerの意図した順番ではありませんが、正しい内容（＝ラベル・値が対応している）が格納できています。にもかかわらず、実際に表示される円グラフは、全く対応できておりません。

```

    Started GET "/records/3/aggregate_result" for ::1 at 2020-06-30 08:09:17 +0900
    Processing by RecordsController#aggregate_result as HTML
      Parameters: {"id"=>"3"}
      User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
      ↳ /Users/user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-5.2.4.3/lib/active_record/log_subscriber.rb:98
       (0.5ms)  SELECT SUM(practice_time) AS sum_practice_time, "practice_item" AS practice_item FROM "records" LEFT OUTER JOIN "practices" ON "practices"."record_id" = "records"."id" WHERE "records"."user_id" = $1 GROUP BY "practice_item"  [["user_id", "3"]]
      ↳ app/controllers/records_controller.rb:59
    test {"多球練習"=>10, "フットワーク"=>30, "サーブ練習"=>50, "オール"=>20}
    
```

※本来の順番は、上の一枚目の画像の通りです。

# コード

Controller

```

    class RecordsController < ApplicationController
    before_action :authenticate_user!
    
      def index
        @q = current_user.records.ransack(params[:q])
        @search_records = @q.result(distinct: true).includes(:practices).page(params[:page]).per(8)
      end
    
      def show
        @record = Record.find(params[:id])
      end
    
      def new
        @record = Record.new
        output = @record.outputs.build
        practice = @record.practices.build
        task = @record.tasks.build
        @item_array = ["サーブ練習","フットワーク", "３球目攻撃","台上処理","多球練習","オール"]
      end
    
      def create
        @record = Record.new(record_params)
        logger.info "###### #{@record.inspect}"
        if @record.save
          flash[:success] = "練習内容の登録が完了しました。"
          redirect_to records_url
        else
          flash[:alert] = "登録に失敗しました。"
          render :new
        end
      end
    
      def edit
        @record = Record.find_by(id: params[:id])
        @item_array = ["サーブ練習","フットワーク", "３球目攻撃","台上処理","多球練習","オール"]
      end
    
      def update
        @record = Record.find_by(id: params[:id])
        if @record.update(record_params)
            flash[:success] = "練習内容の更新が完了しました。"
            redirect_to records_url
          else
            flash[:alert] = "更新に失敗しました。"
            render :edit
          end
      end
    
      def destroy
        record = Record.find_by(id:params[:id])
        record.destroy
    
        redirect_to root_path, notice: "練習記録を削除しました。"
      end
    
      def aggregate_result
      @label = ["3球目攻撃", "多球練習", "サーブ練習", "フットワーク","オール","台上処理"]
      gon.label = @label
      @record = current_user.records.includes(:practices).select(:practice_time).group(:practice_item).sum(:practice_time)
      logger.info "test #{@record.inspect}"
      gon.data = @record.values
      end
    
      private
    
      def set_user
        @user = current_user || User.new
      end
    
      def record_params
        params.require(:record).permit(:record_id, :training_date, :learning_point, outputs_attributes:[:output_name, :id, :_destroy], practices_attributes:[:practice_item, :practice_time, :id, :_destroy], tasks_attributes:[:task_name, :id, :_destroy]).merge(user_id: current_user.id)
      end
    end
    
```

slim

```

    = render 'records/flash_messages'
    h1 レポート
    
    canvas#myPieChart
    script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"
    javascript:
      var ctx = document.getElementById("myPieChart");
      var myPieChart = new Chart(ctx, {
        type: 'pie',
        data: {
          labels: gon.label,
          datasets: [{
              backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(192,240,0,0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(242,68,172,0.2)'
              ],
              data:#{@record.values}
          }]
        },
        options: {
          title: {
            display: true,
            text: '練習内容の内訳'
          }
        }
      });
    
    .d-flex
      .col-6.text-align: center
        = link_to '練習記録一覧に戻る', root_path, class: 'btn btn-primary'
      .col-6.text-align: center
        = link_to '練習記録を登録する', new_record_path, class: 'btn btn-primary'
    
```

db.schema

```

    ActiveRecord::Schema.define(version: 2020_06_29_125236) do
    
      # These are extensions that must be enabled in order to support this database
      enable_extension "plpgsql"
    
      create_table "outputs", force: :cascade do |t|
        t.text "output_name", null: false
        t.bigint "record_id"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.index ["record_id"], name: "index_outputs_on_record_id"
      end
    
      create_table "practices", force: :cascade do |t|
        t.string "practice_item", null: false
        t.integer "practice_time", null: false
        t.bigint "record_id"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.index ["record_id"], name: "index_practices_on_record_id"
      end
    
      create_table "records", force: :cascade do |t|
        t.string "user_id"
        t.text "learning_point", null: false
        t.date "training_date", null: false
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
      end
    
      create_table "tasks", force: :cascade do |t|
        t.text "task_name", null: false
        t.bigint "record_id"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.index ["record_id"], name: "index_tasks_on_record_id"
      end
    
      create_table "users", force: :cascade do |t|
        t.string "email", default: "", null: false
        t.string "encrypted_password", default: "", null: false
        t.string "reset_password_token"
        t.datetime "reset_password_sent_at"
        t.datetime "remember_created_at"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
        t.index ["email"], name: "index_users_on_email", unique: true
        t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
      end
    
      add_foreign_key "outputs", "records"
      add_foreign_key "practices", "records"
      add_foreign_key "tasks", "records"
    end
    
    
```
CC BY-SA 4.0
2020-06-29T23:18:48.397
68123
2020-07-29T14:08:55.340
2020-07-24T11:18:11.903
39475
39475
question
ruby-on-rails ruby chart.js
Chart.jsのラベルと値が対応していない問題を解決したい
`aggregate_result` メソッドを次のように書き換えれば、指定ラベルの順序どおりにグラフが描画されるようになるのではないでしょうか?

```

    def aggregate_result
      # 1. ログインユーザーの親関係にあるRecordテーブルと、
      #   子関係にあるPracticeテーブルの全てのデータを取得する。
      # 2. 取得したデータから、Practiceテーブルのpractice_timeカラムにある
      #   データを選択し、practice_itemごとにデータを分類し、
      #   practice_timeカラムの合計値を計算する。
      # 3. その合計値を、@recordオブジェクトとして表示する。
    
      # MEMO: item_order の順序を参考に Hash を再構築し、その後ひとつの Hash として値を纏める
      item_order = %w[サーブ練習 フットワーク  ３球目攻撃 台上処理 多球練習 オール]
      @record =
        current_user.records
                    .includes(:practices)
                    .select(:practice_time)
                    .group(:practice_item)
                    .sum(:practice_time)
                    .then { |hash| item_order.map { |key| {key => hash[key]} } }
                    .reduce { |hash, key_value| hash.update(key_value) }
    
      logger.info "test #{@record.inspect}"
    
      gon.label = @record.keys
      gon.data = @record.values
    end
    
```

メソッドチェーンを２つ以上使っての数珠繋ぎをやりすぎたパターンだとおもっているので、もしかしたら適切に別名のメソッドを定義して処理を渡してあげる必要があるかもしれません

なにか参考になれば幸いです
CC BY-SA 4.0
2020-07-29T14:08:55.340
69101
2020-07-29T14:08:55.340
3861
68123
answer