Wizardry 🧙

This gem for Rails allows application writers to define a GOV.UK wizard (multi-page form) in one place.

Note this library is at the very early stages of development. It's not properly tested and is very likely to change.

Things the library does:

  • renders the wizard pages based on the specification ✔
  • correctly annotates the pages using Rails' I18n functionality ✔
  • deals with form submissions ✔
  • applies contextual validation on a per-page basis and displaying error messages ✔
  • let developers override pages and questions with their own partials ✔
  • allow for extra customisation over the size of labels, legends and captions ✔
  • allow conditional logic to customise the path through the journey ✔
  • provide a callbacks upon step and wizard completion ✔

How does it work?

The wizard relies on the application having a single model that will hold the collected data. Each question in the wizard maps to a field and every page maps to a validation context.

Throughout the process the last completed step is recorded in the model. It's used to track progress and hold the state of the response. It is automatically updated when a successful submission is made.

Example

Just include the Wizardry module in your controller and use the wizard macro to define your pages and questions:

class RatingsController < ApplicationController
  include Wizardry

  wizard name: 'ratings',
    class_name: 'Rating',
    edit_path_helper: :ratings_page_path,
    update_path_helper: :ratings_path,
    pages: [
      Wizardry::Pages::Page.new(
        :identification,
        title: 'Who are you?',
        questions: [
          Wizardry::Questions::ShortAnswer.new(:full_name),
          Wizardry::Questions::EmailAddress.new(:email)
        ]
      ),
      Wizardry::Pages::Page.new(
        :feedback,
        title: 'What did you think about our service?',
        questions: [
          Wizardry::Questions::ShortAnswer.new(:customer_type),
          Wizardry::Questions::Date.new(:purchase_date),
          Wizardry::Questions::LongAnswer.new(:feedback),
          Wizardry::Questions::Radios.new(:rating, {
            1 => 'Dire', 2 => 'Alright', 3 => 'Average', 4 => 'Decent', 5 => 'Amazing'
          })
        ]
      ),
      Wizardry::Pages::CheckYourAnswersPage.new,
    ]
end

Routes

In the example above, we're providing the edit_path_helper and update_path_helper values. These are the Rails path helpers that correspond with the path that displays the current page of the wizard and the path that updates the object.

Rails.application.routes.draw do
  get %(rating/:page), to: %(ratings#edit), as: :ratings_page
  patch %(rating/:page), to: %(ratings#update), as: :ratings
end

Rendering

To add the wizard content to your edit template, the gem comes with a wizardry_content helper. Additionally, the wizard object is available for the developer to interact with in the @wizard instance variable. Here we are using it to set the heading.

<h1 class="govuk-heading-l"><%= @wizard.current_page.name.capitalize %></h1>

<%= wizardry_content %>

Special pages

Most pages in a wizard are ones that ask questions. Many wizards also contain a check your answers page and a page that's displayed upon completion. These are both in scope for this gem.

Preview

Page one Page two
identification page feedback page