How to add “Save and add another” feature to Rails apps
Tags: rails, ruby, webdev
Published: 2024-06-27 09:00:00

This article was originally published on [Rails Designer](http://railsdesigner.com/save-and-another/).

---

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjomu34rztsy2oaku5wt.jpg)

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.

```ruby
{
  // …
  "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:

```ruby
# …
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](https://guides.rubyonrails.org/action_controller_overview.html#session).

Let's create a form partial first:

```ruby
# 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.

```ruby
# 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](https://railsdesigner.com/turbo-frame-form-validations/).

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.