📊

【Rails】chart.jsを使った投稿数のグラフ化

2023/10/12に公開
2

本の投稿サイトに、chart.jsを使って、投稿数をグラフ化させます!

前回の続きです。
https://zenn.dev/ganmo3/articles/2b5d9e31131e6e

実装要件

  1. 過去7日間分、それぞれの投稿数を一覧表示させる
  2. chart.jsを使って、過去7日分の投稿数のグラフ化

完成イメージ

1. 投稿数の一覧表示

2. chart.jsを使ったグラフ化

1. 投稿数の一覧表示

では投稿数の一覧表示からやっていきます。

モデル記述

bookモデルにメソッドを記載する。

book.rb
scope :created_today, -> { where(created_at: Time.zone.now.all_day) } # 今日
scope :created_yesterday, -> { where(created_at: 1.day.ago.all_day) } # 前日
scope :created_2day_ago, -> { where(created_at: 2.day.ago.all_day) } # 2日前
scope :created_3day_ago, -> { where(created_at: 3.day.ago.all_day) } # 3日前
scope :created_4day_ago, -> { where(created_at: 4.day.ago.all_day) } # 4日前
scope :created_5day_ago, -> { where(created_at: 5.day.ago.all_day) } # 5日前
scope :created_6day_ago, -> { where(created_at: 6.day.ago.all_day) } # 6日前

コントローラ記述

今回はユーザー詳細ページに表示させるため、ユーザーコントローラから呼び出してあげます。

users_controller
  def show
    @user = User.find(params[:id])
    @books = @user.books
    @book = Book.new
    @today_book =  @books.created_today
    @yesterday_book = @books.created_yesterday
    @this_week_book = @books.created_this_week
    @last_week_book = @books.created_last_week
  end

ビュー記述

分かりやすい書き方だと以下の通り書くことができます。

users/show.html.erb
  <h4>7日間分の投稿数</h4>
  <table class='table table-bordered'>
    <thead>
      <tr>
        <th>6日前</th>
        <th>5日前</th>
        <th>4日前</th>
        <th>3日前</th>
        <th>2日前</th>
        <th>1日前</th>
        <th>今日</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><%= @books.created_6day_ago.count %></td>
        <td><%= @books.created_5day_ago.count %></td>
        <td><%= @books.created_4day_ago.count %></td>
        <td><%= @books.created_3day_ago.count %></td>
        <td><%= @books.created_2day_ago.count %></td>
        <td><%= @books.created_yesterday.count %></td>
        <td><%= @books.created_today.count %></td>
      </tr>
    </tbody>
  </table>

よりシンプルな書き方をすると以下のようにもできますので参考までに。

users/show.html.erb
<h4>7日間分の投稿数</h4>
<table class="table table-bordered">
  <tbody>
    <tr>
      <% (6.downto(0)).each do |n| %>
        <td><%= n == 0 ? '今日' : "#{n}日前" %></td>
      <% end %>
    </tr>
    <tr>
      <% (6.downto(0)).each do |n| %>
        <td><%= @books.where(created_at: n.day.ago.all_day).count %></td>
      <% end %>
    </tr>
  </tbody>
</table>

<% (6.downto(0)).each do |n| %>: 数字を6から0までカウントダウンし、n変数に順番に代入させています。
<%= n == 0 ? '今日' : "#{n}日前" %>: n == 0は変数nが0かどうかをチェックしています。もしnが0であれば条件はtrueになり、「今日」というテキストを表示させます。それ以外の場合は、条件がfalseにあり、「n日前」というテキストを表示させます。

2. chart.jsを使って、過去7日分の投稿数のグラフ化

chart.jsを使い、グラフを表示させます!

導入

今回はCDN(Content Delivery Network)を使って使用します。

app/views/layouts/application.html.erb
 <!DOCTYPE html>
 <html>
 <head>
    <!-- その他のヘッダーコード -->
+   <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
 </head>
 <body>
    <!-- ここにコンテンツを配置 -->
 </body>
 </html>

ビュー作成

users/show.html.erb
<canvas id="postCountChart"></canvas>
<script>
  // ページが読み込まれたときの処理
  $(document).on('turbolinks:load', function() {
    // グラフを描画するためのCanvas要素を取得
    var ctx = document.getElementById("postCountChart");
    
    // Chart.jsを使ってグラフを作成
    var postCountChart = new Chart(ctx, {
      type: 'line', // ラインチャートを使用

      data: {
        // グラフのラベル(x軸の値)
        labels: ['6日前', '5日前', '4日前', '3日前', '2日前', '1日前', '今日'],

        datasets: [
          {
            // データセットのラベル
            label: '投稿した本の数',
            
            // データセットの値
            data: [
              <%= @books.created_6day_ago.count %>, // 6日前の投稿数
              <%= @books.created_5day_ago.count %>, // 5日前の投稿数
              <%= @books.created_4day_ago.count %>, // 4日前の投稿数
              <%= @books.created_3day_ago.count %>, // 3日前の投稿数
              <%= @books.created_2day_ago.count %>, // 2日前の投稿数
              <%= @books.created_yesterday.count %>, // 昨日の投稿数
              <%= @books.created_today.count %> // 今日の投稿数
            ],
            
            // グラフの線の色(緑)
            borderColor: "rgba(0, 255, 0, 1)",
            
            // グラフの背景色(透明)
            backgroundColor: "rgba(0, 0, 0, 0)",
            
            // グラフの曲線の滑らかさ(0から1の範囲で設定。数値が大きくなるほど曲線が滑らかになる)
            tension: 0.3
          }
        ],
      },

      options: {
        title: {
          // グラフのタイトル表示
          display: true,
          text: '7日間の投稿数の比較'
        },

        responsive: true, // グラフのレスポンシブデザインを有効化

        scales: {
          y: {
            // y軸(縦軸)の設定。設定しないと自動になるので書かなくても良い。
            suggestedMin: 0, // 最小値を0に設定
            suggestedMax: 10 // 最大値を10に設定
          },
        },
      }
    });
  });
</script>

解説:
基本的な解説はコメントアウトにいれました!
色や曲線は自由にアレンジしてくださいね!

Canvas要素の作成

<canvas id="postCountChart"></canvas>

グラフを表示するために、HTMLに<canvas>要素を作成します。id属性の名前は何でもよいですが、後でJavaScriptからこの要素を参照するために使います。

Turbolinksの無効化

Turbolinksは、Railsでデフォルトで有効になっています。通常のページ遷移では、ページ全体が再読み込みされますが、Turbolinksを使用すると、ページの一部、主に <body> タグ内のコンテンツのみが更新されます。これにより、ページ遷移が高速化されます。
Turbolinksが使われると、ページ遷移したときに、JavaScriptが読み込まれずコードが正しく動作しないことがあります。この問題を回避するために無効化してあげます。

https://zenn.dev/ganmo3/articles/d234583bdc876f

サンプルデータの挿入

グラフがちゃんと表示されるかどうか、毎日投稿し7日間待つのも大変なので、グラフが適切に表示されるかどうかサンプルデータを入れてあげます。
この課題やっているときってまだ勉強しないのですが、チーム開発やポートフォリオ製作でSeedは使っていくので、なんとく触れておくと良いかもです。
以下記事も参考にしてくださいね。

https://zenn.dev/ganmo3/articles/91d0b92ab9c30d

Seedsファイル記述

db内のseeds.rbに以下を記述します。

db/seeds.rb
# 5人のユーザーを作成
5.times do |n|
  user = User.create(
    name: "user#{n+1}", # ユーザー名を設定 ("user1" から "user5")
    email: "test#{n+1}@test.com", # ユーザーのメールアドレスを設定
    password: "123456", # パスワードを一律で設定
  )
  if user.valid?
    puts "User #{n+1} created" # ユーザーの作成をコンソールに出力
  else
    puts "Error creating user #{n+1}: #{user.errors.full_messages.join(', ')}" # エラー表示
  end
end

# それぞれのユーザーに対して、5つの本を作成
User.all.each do |user|
  5.times do |n|
    book = Book.create(
      title: "本#{n+1}", # 本のタイトルを設定
      body: "サンプル投稿です#{n+1}", # 本の本文を設定
      user_id: user.id,  # 本をユーザーに関連付け
      created_at: Time.current - rand(10).day # 本の作成日時を設定(過去10日間からランダムに選択)
    )
    if book.valid?
      puts "Book for User #{user.id} created" # 本の作成をコンソールに出力
    else
      puts "Error creating book for User #{user.id}: #{book.errors.full_messages.join(', ')}" # エラー表示
    end
  end
end

ターミナル実行

ターミナル
rails db:seed

実行画面
コンソールに出さなくてもいいのですが、出した方が分かりやすくて好き。
エラー表示もいれるとポートフォリオで複雑なseedをつくるときに便利です!

データベースのリセット

データベースをリセットしたいときは以下コマンドを実行します。
リセット後、シードデータが再挿入されます。

ターミナル
rails db:reset

完成!
記事100本目~!成果として嬉しい♪
最近はDWC生からフィードバックをいっぱいもらえるの嬉しいです!

続きはこちら↓↓
https://zenn.dev/ganmo3/articles/43148beb95f9c5

Discussion

AirichanAirichan

100!記念すべきですね!!!お疲れ様です♡
なんだか私も嬉しいというか感動です...!
いつも周りを巻き込みながら学びのみではなくて、いい刺激も与えていて、本当にすごいです。

がんもがんも

いつも一緒に喜んでくれてとても嬉しいです♪
ありがとうございます😊
その言葉そのままそっくりあいりさんにお返ししたいです😌笑
あいりさんをきっかけにしていること、見習っていることがたくさんあります
これからもよろしくお願いします🥰