キーワード引数にデフォルト値を設定し, 異なるパターンの引数を取れるようにする


アプリ制作

実現したいこと

リクエストが statistics/activity/from/2019-10-07/to/2019-10-13, statistics/activity/period/prevWeekの2つのパターン両方でグラフ描画を行えるようにする。前者はコントローラのreport_by_dateアクション, 後者はreport_by_periodアクションにルーティングされています。

実装方法

lib下のDateConstraintクラスでURIの/:datebegin, /:dateendを Date.valid_date?メソッドで検証する(year, month, dayでマッチデータオブジェクトを生成してメソッドに代入)

コントローラでparams[:datebegin], params[:dateend]をインスタンス変数にセット

コントローラでweekly, monthlyで場合分けしてReportクラスへ渡す

PERIODSに該当する場合はリダイレクト?

詰まった部分

app/controllers/statistics_controller.rbreport_by_dateアクションで、

GenerateReport::WeeklyReport.newした際にArgumentErrorが発生する。

Image from Gyazo

  • どのように実装してエラーが発生したのか?
#lib/generate_report/report.rb
module GenerateReport
  class Report
    def initialize(user:, column:, period: nil)
      @user = user
      @column = column
      @period = period ? period : nil 
    end
  end 
end


#lib/generate_report/monthly_report.rb
module GenerateReport
  class WeeklyReport < GenerateReport::Report

    attr_reader :column, :date_begin, :date_end

    def initialize(user:, column:, period: nil, date_begin: nil, date_end: nil)
      super(user, column, period)
      @date_begin = date_begin ? date_begin : generate_date_begin(period)
      @date_end = date_end ? date_end : date_begin.end_of_week
    end
    # 省略
  end 
end 

#StatisticsController
class StatisticsController < ApplicationController
  def report_by_date
    @COLUMNS = { activity: "活動量", mood: "気分", appetite: "食欲" }
    set_params_when_report_by_date_action(statistics_params)
    if is_date_weekly?(@date_begin, @date_end)
      @report = GenerateReport::WeeklyReport.new(user: current_user, column: @column, date_begin: @date_begin, date_end: @date_end)
    else
      @report = GenerateReport::MonthlyReport.new(user: current_user, column: @column, date_begin: @date_begin, date_end: @date_end)
    end
    binding.pry
  end
end 
  • ここで実現したいこと
    • statisticsコントローラのreport_by_periodアクションではWeeklyReport.newの引数がuser, column, period の3つ
    • 同コントローラのreport_by_dateアクションではWeeklyReport.newの引数がuser, column, date_begin, date_end の4つ
    • user, columnは両アクションに共通していて、period, date_begin, date_endは存在すれば代入し、無ければinitialize時に別途セットするようにしたい。
  • Report, WeeklyReportクラスの初期化時の引数を修正する
#lib/generate_report/report.rb
class Report
  attr_reader :column, :period, :date_begin, :date_end

  def initialize(user:, column:, period: nil, date_begin: nil, date_end: nil)
    @user = user
    @column = column
    @period = period ? period : nil
  end
  #省略
end 

#lib/generate_report/monthly_report.rb
class WeeklyReport < GenerateReport::Report

  attr_reader :column, :date_begin, :date_end

  def initialize(user:, column:, period: nil, date_begin: nil, date_end: nil)
    super
    @date_begin = date_begin ? date_begin : generate_date_begin(period)
    @date_end = date_end ? date_end : date_begin.end_of_week
  end
  #省略
end

/statistics/activity/prevWeekのリクエスト時

Image from Gyazo

/statistics/activity/from/2019-10-07/to/2019-10-13のリクエスト時

Image from Gyazo

WeeklyReportクラスでintialize時に引数が異なる場合でも, 共通の処理を提供できるようになった。