(Rails)前後の期間のリンクを生成するコードを短く書く

アプリ制作

実現したいこと

体調グラフ機能 

StatisticsControllerに:date_beginまたは:date_end,:period`を受け取り、始まりからperiodを引いた期間又は終わりからperiodを足した期間で情報を取得して、どちらかを返り値で返すメソッドを作る。

考えたこと

例えば、9月1日ー9月30日のグラフを描画する。そこから前月(8月1日ー8月31日)次月(10月1日ー10月31日)に飛びたい。

#前月の始まり, 終わり
ex_begin 
ex_end

# 表示している月の始まり, 終わり
date_begin
date_end

#次月の始まり, 終わり
next_begin
next_end

表示する期間が週/月で2パターンある。それぞれ条件分岐をすると長くなってしまうので、

date_beginまたは date_endのどちらかと periodを受け取り、ex_beginまたはnext_endを返すメソッドをコントローラに用意したい。

#app/controllers/statistics_controller.rb
class StatisticsController < ApplicationController

  #省略
  
  def report
    # クエリパラメータを@reportにセット(Structを使用)
    @report.date_begin = #Dateオブジェクト 2019-9-1
    @report.date_end = #Dateオブジェクト 2019-9-30
    @report.period = :months
    # 省略
    @ex_begin = to_ex_or_next_period(@report.date_begin, @report.period)
    @next_end = to_ex_or_next_period(@report.date_end, @report.period)
  end 

  private
    
  # date_beginまたはdate_endを受け取ってex_beginまたはnext_endを返す
  def to_ex_or_next_period(date, period)
    if (date.cwday == 7) || (date == date.beginning_of_month )
      date.advance(period => -1)
    elsif (date.cwday == 1) || (date == date.end_of_month )
      date.advance(period => 1) #ここがエラーの原因
    else
      raise "pass valid argument"
    end
  end
end 
<!-- app/views/statistics/report.html.erb -->
<%= link_to "前月", statistics_path(column: @report.column, date_begin: @ex_begin, date_end: @report.date_begin - 1, period: @report.period) %>

<p><%= @report.date_begin %>~<%= @report.date_end %></p>

<%= link_to "次月", statistics_path(column: @report.column, date_begin: @report.date_end + 1, date_end: @next_end, period: @report.period) %>

エラーと課題

次月(10月1日ー10月31日)へのリンクをクリックすると、クエリパラメータのdate_endが2019-10-30(月末は31日)となってしまい、raise "pass valid argument"が発動してしまう。

週の終わりまたは月の終わりを返さないといけないが、date.advance(months: 1)ではそれができない。

periodが:weeks, :monthsで条件分岐するとコード長くなってしまう。

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

  • include, exclude
  • SingletonMethod
  • DackTyping
  • 静的型付け言語とRuby(動的型付け言語)の違い