Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
create a functioning wizard for any model in three steps
tree: 5f1bc6aed2

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.



wizardly produces a functional wizard from an ActiveRecord model in three steps.




  • git://



wizardly builds on Alex Kira's validation_group plugin code to DRY up the Rails MVC implementation of a wizard. In three easy steps, wizardly produces the scaffolding and controller of a functioning wizard.

Features include:

  • Model-based definition

  • Wizard controller macro

  • Wizard scaffolding generator

  • Default wizard buttons

  • Custom button creation

  • Page and button callbacks


Install the wizardly gem and require the gem at the bottom of your config/environment.rb file:

require 'wizardly'

For any rails app, run the following to install rake tasks (optional)

./script/generate wizardly_app


Create a working controller wizard for any model in 3 steps. Here's how:

Step 1: Define validation groups for your model.

class User < ActiveRecord::Base    
  validation_group :step1, :fields=>[:first_name, :last_name]
  validation_group :step2, :fields=>[:age, :gender]

Step 2: Tell your controller to act 'wizardly'.

class SignupController < ActionController::Base
  act_wizardly_for :user

Step 3: Generate a 'wizardly' scaffold for your controller.

./script/generate wizardly_scaffold :signup

You are ready to go.

General usage and configuration of wizardly follows.


Default Behavior and Scaffolding Configuration

The wizardly_scaffold generator produces an html view for each validation_group declared in the model. The wizard progresses to each page in the same order of the validation_group(s) in the model. Buttons for navigating the wizard are included on each page.

You can view a wizardly controller's configuration by using the wizardly:config rake task. First you'll need to install it if you already have not

./script/generate wizardly_app

Then you can call the rake task for any controller configured with the 'act_wizardly_for' macro

rake wizardly:config name=signup

Substitute the name of any wizardly controller for 'signup'.

Completing and Canceling

Once a user has entered a wizard, there are two ways they can leave, either by completing or canceling the wizard.

The above example is pretty simple. In fact, no redirects have been defined for completing or canceling the wizard in the above example so the wizardly controller uses the HTTP_REFERER for both cases. What if there is no referer? The controller raises a RedirectNotDefined error. Let's remedy this problem with some options in the macro.

class SignupController < ActionController::Base
  act_wizardly_for :user, :completed=>'/main/finished', 

Now whether the user completes or cancels the wizard, the controller knows how to redirect. Alternately, if you want to redirect to the same page for both cases

class SignupController < ActionController::Base
  act_wizardly_for :user, :redirect=>'/main'

Other options

Here's a list of options you can use in the macro

:completed => '/main/finished'
:canceled => {:controller=>'main', :action=>'canceled'}
:skip => {true|false}
:mask_fields => [:password, :password_confirmation] (by default)

The :skip option tells the scaffold helpers to include or exclude a skip button on every page. The :mask_fields options tells the scaffold generator which fields are html 'password' fields.


The wizardly controller defines five default button functions: next, back, skip, cancel, and finish. All but :skip are used in the scaffolding by default. You can add :skip functionality to all pages by adding an option to the macro

class SignupController < ActionController::Base
  act_wizardly_for :user, :redirect=>'/main', :skip=>true

You can create, customize and change buttons for any controller and any page. See the Advanced Configuration section.


The wizard macro 'act_wizardly_for' creates controller actions for each page. The process for each page is conventional, but hooks (or callbacks) are available for the developer to change the processing. Here's an example. Say our model declares a :step4 validation_group with :username, :password, and :password_confirmation fields. We'd like to handle this step specifically.

class SignupController < ActionController::Base
  act_wizardly_for :user, :redirect=>'/main'

  def on_step4_page_errors
    #clear the password field if errors
    @user[:password] = ''
    @user[:password_confirmation] = ''

The above callback is only called if :step4 does not validate according to its validation_group.

Every page has a set of callbacks. Here's the list for our :step1 page.

def on_get_step1_page; end    # called just before rendering the GET action
def on_step1_page_errors; end # called just before rendering with errors
def on_step1_page_next; end   
def on_step1_page_back; end
def on_step1_page_cancel; end
def on_step1_page_finish; end
def on_step1_page_skip; end

Each callback is defined for the controller object, thus giving it access to all controller variables and methods just as any other action method. Each callback has access to the model through an instance variable using the model's name. So for instance if our model is :user, the instance variable is '@user'. Each wizard page action also defines a @title, @description and @step instance variable. These are primarily used for scaffolding. The @step holds the name of the current validation group, ie. :step1, step2, … in our examples.

Notice the last five callbacks are related to the default wizard buttons. Each callback gives the developer a chance to intervene before the impending render or redirect caused by a button click in the view.

Important: Method names for button callbacks will change if you change the name of the button. For general use, this is not an issue. See the Advanced Configuration section.

Rendering Callback

For anyone needing to handle rendering in a special way, wizardly provides a render call back for this.

class SignupController < ActionController::Base
  act_wizardly_for :user, :redirect=>'/main'

  def render_wizard_page
    respond_to do |format|
      format.xml { render_xml(@step) }

  def render_xml(step)

Advanced Configuration

To be provided


Testing uses RSpec and Webrat. Make sure you have those gems installed. Then to test the development code run the following:

rake spec:all


  • validation_group is currently integrated (plugin not required)

  • ActiveRecord

  • ActionController

Something went wrong with that request. Please try again.