# Best way to split forms into steps?

**URL:** <https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828>\
**Category:** Rails\
**Created:** [April 26, 2006, 11:27am UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828 "2006-04-26T11:27:52Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![robbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/2acd7d/32.png) [@robbie](https://www.ruby-forum.com/u/robbie)\
**Post date:** [April 26, 2006, 11:27am UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828/1 "2006-04-26T11:27:52Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![robbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/2acd7d/32.png) [@robbie](https://www.ruby-forum.com/u/robbie)\
**Post date:** [April 26, 2006, 11:53am UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828/2 "2006-04-26T11:53:26Z")

</div>

Are the 30 fields all from 1 model?

---

<div class="post-metadata">

**Author:** ![robbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/2acd7d/32.png) [@robbie](https://www.ruby-forum.com/u/robbie)\
**Post date:** [April 26, 2006, 12:13pm UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828/3 "2006-04-26T12:13:26Z")

</div>

Chris R. wrote:

> Are the 30 fields all from 1 model?

at the moment yes, I have one table…but if there’s a better way then  
its no biggy to change it.

I was almost thinking of having 3 different tables/models/controllers  
for each step, where step3 belongs\_to step2 which belongs\_to step1.  
This way I could do the validations on each step, if successful then do  
a redirect to the next step…really not sure which is the best way to  
do this though

---

<div class="post-metadata">

**Author:** ![robbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/2acd7d/32.png) [@robbie](https://www.ruby-forum.com/u/robbie)\
**Post date:** [April 26, 2006, 12:35pm UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828/4 "2006-04-26T12:35:43Z")

</div>

thanks very much!

---

<div class="post-metadata">

**Author:** ![robbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/2acd7d/32.png) [@robbie](https://www.ruby-forum.com/u/robbie)\
**Post date:** [April 26, 2006, 12:29pm UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828/5 "2006-04-26T12:29:46Z")

</div>

I’d store the model in the session. I’d do it like this :

def new1  
@employee = Employee.new  
end

def create1  
@employee = Employee.new(params[:employee]) #get the first 10 fields  
…  
insert code here that would fill up the 20-30 fields with valid empty  
data  
…  
if @employee.valid?  
session[:employee]=@employee  
redirect\_to :action=\>“new2”  
else  
render :action=\>“new1”  
end  
end

def new2  
end

def create2  
@employee=session[:employee]  
…  
insert code to empty the 10-20 fields from @employee  
…  
@employee.update\_attributes(params[:employee]) #get fields 10-20  
if @employee.valid?  
session[:employee]=@employee  
redirect\_to :action=\>new3  
else  
render :action=\>“new2”  
end  
end

def new3  
end

def create3  
@employee=session[:employee]  
…  
insert code to empty the 20-30 fields from @employee  
…  
@employee.update\_attributes(params[:employee]) #get fields 20-30  
if @employee.save  
flash[:notice] = ‘Employee was successfully updated.’  
…  
else  
render :action=\>“new3”  
end  
end

This code could do with some improving, but it gives a general idea of  
how you could do it.

---

<div class="post-metadata">

**Author:** ![robbie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/2acd7d/32.png) [@robbie](https://www.ruby-forum.com/u/robbie)\
**Post date:** [April 26, 2006, 4:45pm UTC](https://www.ruby-forum.com/t/best-way-to-split-forms-into-steps/58828/6 "2006-04-26T16:45:08Z")

</div>

On 4/26/06, robbie shepherd [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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](http://www.kylemaxwell.com/articles/2006/02/06/fun-with-single-table-inheritance)

> 

and

[http://www.bigbold.com/snippets/posts/show/277](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
