Over a million developers have joined DZone.

RoR Multi-step Forms

·
Here's a controller code snippet for doing partial validations on Rails model objects:
  private
    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


To ensure the errors are cleared out properly on each request add a before_filter with the following:
    def clear_stage_errors
      unless @session['partial_user'].nil?
        @session['partial_user'].errors.clear
      end
    end


You can use get_partial_user_from_session and save_partial_user_in_session as before and after filters, respectively, so you only have to reference @user in your multi-step controller.

A clean way to arrange the view is to have each step in its own partial, and set a variable such as @current_stage in your controller, then in your view just do something like:

<%= start_form_tag({:action=> "signup"} , { :name => 'signupform' }) %>
<%= hidden_field_tag "changeCountry" %>
<%= hidden_field_tag "current_stage", "#{@current_stage}"%>

Registration Process

<%= @flash['notice'] %> <%= render_partial "#{@current_stage}" %> <%= end_form_tag %>
Your signup controller action could something similar to this: def signup case @request.method when :post @current_stage = @params['current_stage'] if @current_stage == "stage1" @user.attributes = @params['user'] @current_stage = "stage2" if valid_for_attributes(@user,["login","attribute2"]) end elsif @current_stage == "stage2" @user.attributes = @params['user'] @current_stage = "stage3" if valid_for_attributes(@user,["attribute3","attribute4"]) elsif @current_stage == "stage3" @user.attributes = @params['user'] if @user.save @session[:user] = User.authenticate(@user.login, @params['user']['password']) flash['notice'] = "Signup successful" redirect_to :action => "home" end end when :get @current_stage = "stage1" end end
Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}