DEV Community

Cover image for How to add “Save and add another” feature to Rails apps
Rails Designer
Rails Designer

Posted on • Edited on • Originally published at railsdesigner.com

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

This article was originally published on Rails Designer.


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.

Image description

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"
}
Enter fullscreen mode Exit fullscreen mode

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
# …
Enter fullscreen mode Exit fullscreen mode

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.

🎨 Rails Designer is a professionally designed UI components library for Rails. Built with ViewComponent. Designed with Tailwind CSS. Enhanced with Hotwire. Build beautiful, faster.

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 %>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)