Skip to content

Instantly share code, notes, and snippets.

@dogweather
Created May 11, 2015 23:02
Show Gist options
  • Save dogweather/e63e2adc93caede15df2 to your computer and use it in GitHub Desktop.
Save dogweather/e63e2adc93caede15df2 to your computer and use it in GitHub Desktop.
An example of a "wizard" in Rails
require 'types'
class RsvpController < ApplicationController
include Wicked::Wizard
steps :get_visitor_kind, :get_gender, :choose_events, :confirmation, :thank_you, :cancel_visit
before_filter :get_user, :except => :sign_in
def show
case step
when :get_visitor_kind
# Clear any chosen events in case the user is coming back here
# from the next steps.
@user.clear_itinerary
@user.restart_visit # In case this user had canceled in the past
@user.save(:validate => false)
when :get_gender
unless @user.should_have_gender?
skip_step
end
# Show the gender dialog.
# Give the user a default gender.
if @user.gender.nil?
@user.gender = 'female'
@user.save(:validate => false)
end
@header = 'Please indicate your gender'
when :choose_events
# Set up the calendar.
@events = make_event_list
@notices = make_notice_list
when :confirmation
# Show the itinerary chosen in the previous step.
# Present the form for biographical data.
# Get the user's approval.
@submit_label = session[:updating] ? 'Save Changes' : 'Sign me up'
@header = session[:updating] ? 'Change Your Reservation' : 'Confirm Your Visit'
@back_label = session[:updating] ? '<i class="icon-chevron-left"></i> Make Changes'.html_safe : back_button_label
when :cancel_visit
# Delete the visit, update the spreadsheets and send emails.
# Finally, the cancel_visit template shows a "sorry to see you
# go" message.
@visit_date = @user.visit_date
@user.cancel_visit
Resque.enqueue(VisitSystem::ExportUserJob, @user.id, @site.id)
UserMailer.cancellation_confirmation(@user, @site, @visit_date).deliver
when :thank_you
# Update the visible capacity numbers, export the data, send out
# emails, and show a thank you page.
@user.update_capacities_for_current_itinerary
@return_url = update_rsvp_url(@user.sign_in_token)
UserMailer.signup_confirmation(@user, @return_url, session[:updating] == true, @site).deliver
Resque.enqueue(VisitSystem::ExportUserJob, @user.id, @site.id)
when :finish
# The wizard will automatically redirect to the home page.
else
raise "Unexpected step in show: #{step}"
end
render_wizard
end
def update
case step
when :get_visitor_kind
# Returning from the visitor kind buttons.
set_visitor_kind
when :get_gender
set_gender
when :confirmation
update_user
else
raise "Unexpected step: #{step}"
end
end
def index
# Should never be used
redirect_to root_path
end
def itinerary_done_button
render :partial => 'itinerary_done_button'
end
# Handle token-based sign-ins. Try to find a user matching the
# token. Set up the session and redirect to the confirmation screen.
def sign_in
u = User.find_by_sign_in_token params[:token]
unless u.nil?
set_user(u)
session[:updating] = true
# Now, if this returning user has canceled, we show them a
# special page. Otherwise, send them back to the
# confirmation/biographical info form.
if u.canceled?
u.restart_visit
redirect_to root_path #For now, not too special. :-) TODO: Make special.
else
redirect_to wizard_path(:confirmation)
end
else
render :nothing => true, :status => :forbidden
end
end
private
def set_visitor_kind
visitor_kind_id = params.keys.select{|k| k.start_with? 'commit'}.first.sub('commit-','')
visitor_kind = VisitorKind.find visitor_kind_id
raise "Couldn't find the visitor kind with id #{visitor_id} in #{params.inspect}" if visitor_kind.nil?
@user.visitor_kind = visitor_kind
@user.highschool_grad_year = visitor_kind.hs_graduation_year
@user.college_enrollment_year = visitor_kind.college_enrollment_year
@user.college_enrollment_semester = 'Fall'
@user.save(:validate => false)
skip_step
render_wizard
end
def set_gender
@user.update_attributes(params[:user])
g = params[:gender_options]
unless g == 'specify'
@user.gender = g
end
@user.save(:validate => false)
skip_step
render_wizard
end
def update_user
@user.update_attributes(params[:user])
unless @user.should_have_gender?
g = params[:gender_options]
unless g == 'specify'
@user.gender = g
end
end
render_wizard @user
end
def make_one_kind_per_day(events)
event_hash = {}
for e in events
index = [e.start_date, e.event_kind.name]
event_hash[index] = e.event_kind
end
return event_hash.values.sort
end
def make_notice_list
starting = Time.zone.now.to_date
starting += 1.week unless admin?
ending = (starting + 6.months).end_of_month
notices = Notice.where(:display_on=>(starting..ending))
return notices
end
def make_event_list
starting = Time.zone.now.beginning_of_day
starting += 1.week unless admin?
ending = (starting + 6.months).end_of_month
events = Event.for_user(@user).where(:starts_at=>(starting..ending))
# Convert from a flat list of events to an array-hash
# of event kinds keyed by date
event_hash = ArrayHash.new
for e in events
event_hash[e.start_date] << e.event_kind
end
# Process each day's event kinds: sort, make unique,
# and communicate the name and css class.
for day in event_hash.keys
event_hash[day].uniq!
event_hash[day].sort!
event_hash[day].map!{|ek| {name: ek.name, css_class: css_class_for_event_kind(ek)}}
end
return event_hash
end
def css_class_for_event_kind(e)
return "event-kind-#{e.id % COLORS.length}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment