Form step-by-step in Rails

Sebastián Vidal Aedo
3 min readApr 19, 2022

--

Sometimes we have a very large (or complicated) form and it’s necessary to separate it into several parts, something like an installation wizard with several steps. This make better the user experience and don’t show an infinite form. In addition, on the application side, it helps us to save / validate step by step in a very correct way.

wtf? form

To implement this I thought in 2 options, one in full JS on the client side and another more Rails style.

:)

Option 1: JS

Each step can be a div, we hide all of them and only show the “current” one. For this we implement a simple function that hides the divs and with a parameter that we pass to it we know which one we should show. This is easy to implement and its use from buttons like next and previous is very easy to implement.

The problem? that everything remains as a client load, the “giant” form continues to be sent to the front and all the work is delivered to the front, which does not solve performance and prevents us from validating / saving at each step using the different RoR tools .

Option 2: Rails

“Wicked”?

Wicked is a gem that will allow us to create this step-by-step form that we are looking for, being able to save / validate at each stage.
Configuration is more complex than using just JS, but the result is much more scalable and robust.

An example

Let’s imagine that we have a Product object with name, price and color and we want to separate the creation of a product into 3 steps.

rails g migration create_products name color price

In a Controller we incorporate Wicked, define the steps and render the wizard.

# app/controllers/product_steps_controller.rbclass ProductStepsController < ApplicationController
include Wicked::Wizard
steps :name, :price, :color
def show
render_wizard
end

Add this new reference to routes inside products section

# config/routes.rbRails.application.routes.draw do 
root 'pages#index'
resources :products, only: [:create, :show] do
resources :product_steps, only: [:show, :update]
end
end

create is because in the first step we create the object, then we are going updating it.

For each of the steps we create a view with the name associated with each step. Each of these views is a form associated with a created object that handles certain Wicked parameters, such as wizard_path and previous_wizard_path.

app/views/product_steps/name.html.erb
app/views/product_steps/price.html.erb
app/views/product_steps/color.html.erb

Begin the proccess

<%= link_to 'New Product', products_path, method: :post %>

Next? back? end?

# app/views/product_steps/price.html.erb<%= form_with(model: @product, url: wizard_path, local: true) do |f| %>
<%= f.label :price %>
<%= f.text_field :price %>

<%= link_to ‘Back’, previous_wizard_path %>
<%= f.submit ‘Next’ %>
<% end %>

Add and update action in controller to save in any step and an action to end the wizard proccess

def update
product.update(product_steps_params)
render_wizard @product
end
def finish_wizard_path
product_path(product)
end

Here is an example code https://github.com/sebavidal10/rails-form-wizard

--

--

Responses (1)