#217 Multistep Forms
See how to create a multistep (wizard) form from scratch in this episode.
- Download:
- source codeProject Files in Zip (94.3 KB)
- mp4Full Size H.264 Video (22.7 MB)
- m4vSmaller H.264 Video (15.7 MB)
- webmFull Size VP8 Video (44.8 MB)
- ogvFull Size Theora Video (31.4 MB)
Resources
bash
script/generate nifty_scaffold order shipping_name:string billing_name:string index show new
script/generate nifty_scaffold order shipping_name:string billing_name:string index show new
models/order.rb
attr_writer :current_step
validates_presence_of :shipping_name, :if => lambda { |o| o.current_step == "shipping" }
validates_presence_of :billing_name, :if => lambda { |o| o.current_step == "billing" }
def current_step
@current_step || steps.first
end
def steps
%w[shipping billing confirmation]
end
def next_step
self.current_step = steps[steps.index(current_step)+1]
end
def previous_step
self.current_step = steps[steps.index(current_step)-1]
end
def first_step?
current_step == steps.first
end
def last_step?
current_step == steps.last
end
def all_valid?
steps.all? do |step|
self.current_step = step
valid?
end
end
attr_writer :current_step validates_presence_of :shipping_name, :if => lambda { |o| o.current_step == "shipping" } validates_presence_of :billing_name, :if => lambda { |o| o.current_step == "billing" } def current_step @current_step || steps.first end def steps %w[shipping billing confirmation] end def next_step self.current_step = steps[steps.index(current_step)+1] end def previous_step self.current_step = steps[steps.index(current_step)-1] end def first_step? current_step == steps.first end def last_step? current_step == steps.last end def all_valid? steps.all? do |step| self.current_step = step valid? end end
orders_controller.rb
def new
session[:order_params] ||= {}
@order = Order.new(session[:order_params])
@order.current_step = session[:order_step]
end
def create
session[:order_params].deep_merge!(params[:order]) if params[:order]
@order = Order.new(session[:order_params])
@order.current_step = session[:order_step]
if @order.valid?
if params[:back_button]
@order.previous_step
elsif @order.last_step?
@order.save if @order.all_valid?
else
@order.next_step
end
session[:order_step] = @order.current_step
end
if @order.new_record?
render "new"
else
session[:order_step] = session[:order_params] = nil
flash[:notice] = "Order saved!"
redirect_to @order
end
end
def new session[:order_params] ||= {} @order = Order.new(session[:order_params]) @order.current_step = session[:order_step] end def create session[:order_params].deep_merge!(params[:order]) if params[:order] @order = Order.new(session[:order_params]) @order.current_step = session[:order_step] if @order.valid? if params[:back_button] @order.previous_step elsif @order.last_step? @order.save if @order.all_valid? else @order.next_step end session[:order_step] = @order.current_step end if @order.new_record? render "new" else session[:order_step] = session[:order_params] = nil flash[:notice] = "Order saved!" redirect_to @order end end
orders/new.html.erb
<% form_for @order do |f| %>
<%= f.error_messages %>
<%= render "#{@order.current_step}_step", :f => f %>
<p><%= f.submit "Continue" %></p>
<p><%= f.submit "Back", :name => "back_button" unless @order.first_step? %></p>
<% end %>
<% form_for @order do |f| %> <%= f.error_messages %> <%= render "#{@order.current_step}_step", :f => f %> <p><%= f.submit "Continue" %></p> <p><%= f.submit "Back", :name => "back_button" unless @order.first_step? %></p> <% end %>

