codeforamerica/michigan-benefits

View on GitHub
app/controllers/steps_controller.rb

Summary

Maintainability
A
3 hrs
Test Coverage
class StepsController < ApplicationController
  layout "step"

  before_action :ensure_application_present, only: %i(edit index update)
  before_action :maybe_skip, only: :edit

  helper_method :decoded_step_path
  helper_method :application_title

  class StepNotFoundError < StandardError; end

  def ensure_application_present
    if current_application.blank?
      redirect_to first_step_path
    end
  end

  def current_application
    snap_application || medicaid_application
  end

  def edit
    attribute_keys = Step::Attributes.new(step_attrs).to_sym
    @step = step_class.new(existing_attributes.slice(*attribute_keys))
  end

  def update
    @step = step_class.new(step_params)

    if @step.valid?
      update_application
      redirect_to(next_path)
    else
      render :edit
    end
  end

  def self.to_param
    controller_path.dasherize
  end

  def self.step_class
    controller_path.classify.constantize
  rescue NameError
    raise StepNotFoundError,
      "Step not found: #{controller_path.classify}. "\
      "Create the step or override `<controller>#step_class` "\
      "so that it returns `NullStep`"
  end

  def next_path(params = {})
    next_step = step_navigation.next
    decoded_step_path(step: next_step, params: params) if next_step
  end

  # This is an intentional noop
  def step_navigation; end

  # This is an intentional noop
  def application_title; end

  def snap_application
    SnapApplication.find_by(id: session[:snap_application_id])
  end

  def medicaid_application
    MedicaidApplication.find_by(id: session[:medicaid_application_id])
  end

  private

  delegate :step_class, to: :class

  # Redefine me

  def update_application
    current_application.update!(step_params)
  end

  def existing_attributes
    HashWithIndifferentAccess.new(current_application&.attributes)
  end

  def skip?
    false
  end

  # Probably don't redefine me

  def single_member_household?
    current_application.members_count == 1
  end

  def multi_member_household?
    current_application.members_count > 1
  end

  def step_params
    params.fetch(:step, {}).permit(*step_attrs)
  end

  def step_attrs
    step_class.attribute_names
  end

  def current_path(params = nil)
    decoded_step_path(params: params)
  end

  def maybe_skip
    if skip? && going_backwards?
      redirect_to previous_path(rel: "back")
    elsif skip?
      redirect_to next_path
    end
  end

  def previous_path(params = nil)
    previous_step = step_navigation&.previous
    if previous_step
      decoded_step_path(step: previous_step, params: params)
    else
      root_path
    end
  end

  def going_backwards?
    params["rel"] == "back"
  end

  def skip_path(params = nil)
    skip_step = step_navigation.skip
    decoded_step_path(step: skip_step, params: params) if skip_step
  end

  def array_to_checkboxes(array)
    array.map { |key| [key, true] }.to_h
  end

  def checkboxes_to_array(checkboxes)
    checkboxes.select { |k| step_params[k].in?(["1", 1, true]) }.map(&:to_s)
  end

  def decoded_step_path(step: self.class, params: nil)
    step_path(step, params).gsub("%2F", "/")
  end

  def first_step_path
    root_path
  end
end