On 4/26/06, robbie shepherd [email protected] wrote:
I have a form with about 30+ fields, which the client is wanting to
separate into 3 pages/steps - just wondering what is the best way to go
about this, specifically remembering data entered, from one page to
another, and making sure the various bits of data are validated
correclty, error messages outputted etc etc…
is there a best practice method for doing this?
I had to do the exact same thing. I found two different articles
regarding
how to implement this type of thing:
<
http://www.kylemaxwell.com/articles/2006/02/06/fun-with-single-table-inheritance
and
http://www.bigbold.com/snippets/posts/show/277
I tried the first link but wasn’t able to get it to work (and I also
preferred the second method). I changed the second method to make it a
bit
more dynamic. Here’s what I’m using right now, which also does
validation
on the fields before creating the new record (by the way, if anyone else
has
any other methods for implementing multi-part forms, please post them!):
class UserController < ApplicationController
before_filter :clear_stage_errors, :get_partial_user_from_session
after_filter :save_partial_user_in_session
def initialize
# here we provide the names of the fields that we want to be
validated
# at each stage, where stage1 corresponds to the fields listed in
@stages[0]
@stages = [ %w(first_name last_name address1 country city state
zip_code
birth_date phone1 email),
%w(radio_stations personal_genres),
%w(live_performance_frequency),
%w(employment_experience ),
%w(some_field some_other_field)
]
end
def signup
case @request.method
when :post
# current_stage is stored in a hidden form field
@current_stage = @params[:current_stage].to_i
# if user hit the previous button, decrement the current stage
if @params['imgPrevious.x']
@current_stage -= 1
return;
end
@user.attributes = @params['user']
if (@current_stage >= @stages.length) &&
(valid_for_attributes(@user,
@stages[@current_stage - 1]))
if @user.save
# if we don't reset the @user ivar to nil, whenever we access
the
signup
# form, it keeps repopulating the contents of the fields with
the
previously
# entered information
@user = nil
# you might not want to reset the session here, if so, remove
this
next line
reset_session
flash[‘notice’] = “Signup successful”
redirect_to :action => :index, :controller => “site”
return
end
else
# move on to the next stage only if we can validate all the
attributes for the current stage
if (valid_for_attributes(@user, @stages[@current_stage - 1]))
@current_stage += 1
end
end
when :get
# since the request is a get, we fetch the first stage
@current_stage = 1
end
end
def get_partial_user_from_session
unless @session[‘partial_user’].nil?
@user = @session[‘partial_user’]
else
@user = User.new
end
end
def save_partial_user_in_session
unless @user.nil?
@session[‘partial_user’] = @user
end
end
Might be a good addition to AR::Base
def valid_for_attributes( model, attributes )
unless model.valid?
errors = model.errors
our_errors = Array.new
errors.each { |attr,error|
if attributes.include? attr
our_errors << [attr,error]
end
}
errors.clear
our_errors.each { |attr,error| errors.add(attr,error) }
return false unless errors.empty?
end
return true
end
end
in models/user.rb
class User < ActiveRecord::Base
validates_presence_of :first_name, :last_name, :address1, :city,
:state,
:country, :zip_code, :phone1, :email, :birth_date, :radio_stations,
:personal_genres, :live_performance_frequency
end
in views/user/signup.rhtml:
<%= start_form_tag({:action=> “signup”} , { :name => ‘signupform’,
:multipart => true } ) %>
<%= hidden_field_tag “current_stage”, @current_stage %>
<%= @flash[‘notice’] %>
<%= render_partial “stage#{@current_stage}” %>
<% if @current_stage != 1 %>
<% end %>
<%= end_form_tag %>
and then place each of your stages with your text_fields, checkboxes,
form
elements, etc into views/user/[_stage1.rhtml, _stage2.rhtml,
_stage3.rhtml,
…] ie:
in _stage1.rhtml:
First Name: |
<%= text_field 'user', 'first_name' %> |
Middle Initial: |
<%= text_field 'user', 'middle_initial' %> |
good luck,
Mike