Weeklyグラフで前後の期間へのリンク生成で発生するエラーをデバッグ


アプリ制作

実現したいこと1

リクエストが下の2つのパターン両方でグラフ描画を行えるようにする。前者はコントローラのreportbydateアクション, 後者はreportbyperiodアクションにルーティングされている。

statistics/activity/from/2019-10-07/to/2019-10-13, statistics/activity/period/prevWeek

課題1

statistics/activity/period/prevWeekで先週のグラフを表示する。これは2019-10-07/to/2019-10-13の期間のグラフが表示できている。

(1) 次に前週へのリンクを押し, 2019-09-30 ~ 2019-10-06の期間のグラフを表示する。しかし、この期間のレコードは存在するのにグラフには該当日付のY軸の値が表示されない。

(2) そのまたさらに前週へのリンクを押すと, 本来は2019-09-23 ~ 2019-09-29の期間がリクエストされるはずにもかかわらず, 2019-08-01 ~ 2019-09-29の期間がリクエストされる。

課題1がなぜ起こるのか?・修正すべき点と結果

binding.pryでコントローラの@reportが正しく生成されているか確認をした。

Image from Gyazo

2019-09-30 ~ 2019-10-06の期間, つまり1週間でリクエストをしているのに、MonthlyReportクラスが呼ばれていた。(期間が1ヶ月単位の時に呼び出すように設計したつもりだった)

リクエストされた期間に対して, コントローラ内でWeeklyReportかMonthlyReportかを条件分岐する部分が意図した通りに機能していない。その部分を修正する必要がある。

コントローラではis_date_weekly?メソッドでtrueならWeeklyReport, falseならMonthlyReportを生成するように分岐させていた。2019-09-30 ~ 2019-10-06のリクエストに対して, このメソッドでfalseを返してしまい, MonthlyReportが生成されてしまっていた。

def is_date_weekly?(date_begin, date_end)
  (date_begin..date_end).to_a.length <= 7 ? true : false
end

なぜそうなるかというと、メソッドの引数date_begin, date_endがStringクラスのまま代入されていた。Dateオブジェクトに変換するように修正すると, WeeklyReportを生成できた。

さらに発生した懸念点

MonthlyReportクラスではgroup_by_monthで月初の日付をキーにしてグループ化したハッシュを作成している。そのためdate_beginが月初の日付でないと, 該当期間のY軸の値をすべてnilにして配列で返してしまう.

(この,keyが見つからない場合にnilの配列を返す処理は, Diaryレコードがない期間のリクエストの際にエラー発生を防ぐ目的で実装していた。)

def data_generator(user, column, date_begin)
  records = user.diaries.group_by_month(&:diary_date)
  if records[date_begin].present?
    records[date_begin].map do |diary|
      diary.send(column)
    end
  elsif records[date_begin].nil?
    date_range.length.times.map { |n| nil }
  else
    raise "Error"
 end

グループしたHashのキーが存在しなかった場合, 該当期間のY軸がすべてnilになる可能性がある。group_byメソッドの処理を確認したり、Reportクラスの処理を修正する必要があるなと思った。

実現したいこと2

同じカラムで週間→月間, 月間→週間の遷移をする

どのように実装したか?

  1. 週間→月間
    • WeeklyReportクラスにto_monthlyメソッドを作成
    • date_beginのbeginning_of_month, end_of_monthを取得して, URI文字列を返す
  2. 月間→週間
    • MonthlyReportクラスにto_weeklyメソッドを作成
    • date_beginとdate_endの日数の差の2分の1の日付を基準日にし、基準日の週の月曜, 日曜をそれぞれdate_begin, date_endにセット
    • URI文字列を返す

Viewで@reportがWeekly, Monthlyどちらのクラスのインスタンかを確かめる

#app/views/statistics/report_by_date.html.erb
<% if @report.class.method_defined? :to_monthly %>
  <%= link_to "月間", "#{@report.to_monthly}" %>
<% end %>
<% if @report.class.method_defined? :to_weekly %>
  <%= link_to "週間", "#{@report.to_weekly}" %>
<% end %>

実装できた。

ここまでに実装した機能(体調グラフ)

  • URIの形式

    • 期間を表す単語で期間を指定する

      /statistics/:column/period/thisWeek

      • 単語は4種類 [thisWeek, thisMonth, prevWeek, prevMonth]

      • PeriodConstaraintクラスでリクエストのURIをこれら4種類のみに限定

    • 日付で期間を指定

      /statistics/:column/from/:date_begin/to/:date_end

      • DateConstraintクラスで日付を表す文字列かどうかを検証
  • 期間は週間、月間の2週類

  • それぞれの期間について、以下のことができる.

    • 前後の期間へのリンクを生成する機能(同カラム内)
    • 週間→月間、月間→週間へのリンクを生成する機能(同カラム内)
  • 同期間内で異なるカラムへのリンクを生成する機能

プロを目指す人のためのRuby入門

  • 第10章 Procとyieldを理解する(2時間)