How to add “Save and add another” feature to Rails apps

3D rendering of a scale,  with bright, summer colors

If your app has a business model that often is created in sequence (think tasks or products), the Save and add another UX paradigm can be a great option.

I stumbled upon a great example in the Linear app.

Previously articles often show a solution using two buttons. Then based on the value of the commit key (i.e. the button’s value) in the params, determine which branch is needed within the create action of the controller.

{
  // 
  "product": {
    "name": "Example Product",
    "description": "This is an example product",
    "price": "9.99"
  },
  "commit": "Save and Add Another",
  "controller": "products",
  "action": "create"
}

Given above params within your controller’s action you can do something like this:

# …
if params[:commit] == "Save and Add Another"
  # Redirect to the new action
  redirect_to new_product_path, notice: "Product created successfully, add another."
else
  redirect_to products_path, notice: "Product created successfully."
end
# …

Technically the “checkbox” solution (from Linear) works the same, but instead of checking the button’s value, let’s check for a truthy value of a checkbox. I prefer this UX over giving the user two buttons as it’s cleaner, but also allows to persist the “add another checkbox” using Rails’ session storage.

Let’s create a form partial first:

# app/views/products/new.html.erb
<%= form_with model: @product do |form| %>
  <⁠%= form.label :name %>
  <%= form.text_field :name %>

  <%= form.label :description %>
  <%= form.text_field :description %>

  <%= form.label :price %>
  <%= form.number_field :price %>

  <%= form.check_box :add_another, { checked: session[:add_another] } %>
  <%= form.label :add_another, "Add another after saving" %>

  <%= form.submit "Save" %>
<% end %>

See how the session is checked for a add_another key. It’s set in the controller’s action. Let’s look at it now.

# app/controllers/products_controller.rb
class ProductsController < ApplicationController
  def new
    @product = Product.new

    session[:add_another] ||= false
  end

  def create
    @product = Product.new(product_params)
    session[:add_another] = params[:product][:add_another] == "1"

    if @product.save
      if session[:add_another]
        redirect_to new_product_path, notice: "Product added, you can add another."
      else
        redirect_to products_path, notice: "Product created successfully."
      end
    else
      render :new, status: :unprocessable_entity
    end
  end
  # …
end

The add_another value is stored in the session and then checked in both the new action, to toggle the checkbox to either true or false and then to set the value in the session in the create action.

Of course redirecting to the new page is not the most graceful option and you might show the product form in a modal. If that’s the case, check out this article on how to use Turbo Streams to replace a modal with a new form.

You could do whatever else you want to do using Turbo-Streams: replace the form and so on.

And that’s how easy it is to get this UX in your Rails app.

Get UI & Product Engineering Insights for Rails Apps (and product updates!)

Published at . Last updated at . Have suggestions or improvements on this content? Do reach out.

UI components for Ruby on Rails apps

$ 129 one-time
payment

Get Access
  • One-time Payment

  • Access to the Entire Library

  • Built using ViewComponent

  • Designed with Tailwind CSS

  • Enhanced with Hotwire