Last active
May 12, 2020 15:08
-
-
Save jebw/c8409c2e70815f07cc5631a148525a77 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Just an abstracted hash data store | |
# For now can be backed by session data, later on maybe redis | |
class Store | |
attr_reader :data | |
delegate :[], to: :data | |
def initialize(data) | |
@data = data | |
end | |
def fetch(*keys) | |
data.slice Array.wrap(*keys) | |
end | |
end | |
## Parent class for Step | |
## Steps know about their parent(s) - think the Git Commit data structure | |
## Can determine if a step follows another step by checking if the step is in the 'current steps' parents list | |
class Step | |
include ActiveModel::Model | |
include ActiveModel::Attributes | |
class << self | |
def step_key | |
model_name.to_param | |
end | |
end | |
def initialize(store) | |
@store = store | |
assign_attributes_from_store | |
end | |
def assign_attributes_from_store | |
assign_attributes store.fetch(attribute_names) | |
end | |
def active? | |
true | |
end | |
def inactive? | |
!active? | |
end | |
def valid_if_active? | |
inactive? || valid? | |
end | |
## Already has access to the store, so save its attributes into the store | |
def save | |
return false unless active? && valid? | |
# do something to record attributes in @store | |
end | |
def follows?(step) | |
parents.include?(step) && active? | |
end | |
end | |
## Defines all the steps and has methods for moving between steps | |
## and determining the current position based off data in the store | |
class Journey | |
STEPS = [ | |
Identity, | |
Address | |
].index_by(&:step_key) | |
def initialize(store) | |
@store | |
end | |
def step(step_name) | |
STEPS[step_name].new @store | |
end | |
def next_step(current_step) | |
current_step = STEPS[current_step] if current_step.is_a?(Symbol) | |
all_steps.find do |step| | |
step.follows?(current_step) | |
end | |
end | |
def calculate_next_step | |
# More convoluted walking through data we have | |
# For each step | |
# Is it active | |
# is it invalid? | |
# end | |
# end | |
end | |
def all_steps_valid? | |
all_steps.all?(:valid_if_active?) | |
end | |
def all_steps | |
STEPS.keys.map(&method(:step)) | |
end | |
end | |
## Models, PARENTS array is just used for controlled the DAG | |
class Identity < Step | |
PARENTS = [].freeze | |
attribute :firstname | |
attribute :lastname | |
attribute :email | |
attribute :date_of_birth, :date | |
validates :firstname, presence: true | |
validates :lastname, presence: true | |
validates :email, presence: true, format: /@/ | |
validates :date_of_birth, presence: true | |
end | |
class Address < Step | |
PARENTS = [Identity].freeze | |
attribute :line1 | |
attribute :line2 | |
attribute :line3 | |
attribute :postcode | |
validates :line1, presence: true | |
validates :line2, presence: true | |
validates :postcode, presence: true, format: POSTCODE_FORMAT_REGEX | |
## Models determine themselves whether they are the current journey | |
## Actual logic is code so can be anything but assumption is it'll check | |
## values in the store from earlier steps | |
def active? | |
store[:firstname].present? || store[:lastname].present? || store[:email].present? | |
end | |
end | |
Rails.application.routes.draw do | |
namespace :apply do | |
## Single route, single controller | |
## Determines model to use from the params[:id] => that has the steps param key in | |
resources :steps, only: [:show, :update] | |
end | |
end | |
## Single controller, basic RESTful | |
## Step model used determined from params[:id] | |
## Some funk in private methods for setting up Store and Journey classes | |
class StepsController do | |
before_action :check_step_is_active | |
def show; end | |
def update | |
current_step.assign_attributes attribute_params | |
if current_step.save | |
redirect_to_next_step | |
else | |
render :show | |
end | |
end | |
private | |
def store | |
Store.new applydata | |
end | |
def applydata | |
session[:applydata] ||= {} | |
end | |
def current_step | |
journey.step params[:id] | |
end | |
helper_method :current_step | |
def journey | |
Journey.new store | |
end | |
def check_step_is_active | |
return true if current_step.active? | |
redirect_to_correct_step | |
end | |
def redirect_to_next_step | |
redirect_to step_path journey.next_step(current_step) | |
end | |
def redirect_to_correct_step | |
redirect_to step_path journey.calculate_next_step | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment