How to implement and customize Rails Flash Messages (notifications)

Abstract, minimalistic hero image depicting a stylized notification bubble in shades of blue and gray, representing communication and immediacy in a Rails application.

Flash has been a feature of Rails since the earliest version, and besides some refinements, the functionality stayed the same.

The Rails flash feature is an easy way to pass temporary messages, like success messages or error notices, from controllers to views, it’s stored in the user’s session and immediately cleared out after display. Thus they’ll be gone by the time the next action is performed.

The most basic version, that’s been around since the first version, looks like this:

# app/controllers/users_controller.rb
def create
  if @user.save
    flash[:notice] = "User Saved"
    redirect_to @user
    # or: redirect_to @user, notice: "User Saved"
  end
end
<div id="flash">
  <% if flash[:notice] %>
    <div class="notice">
      <%= flash[:notice] %>
    </div>
  <⁠% end %>
</div>

When to use Rails flash message?

I’ve seen flash messages often been used incorrectly. So when should you show a flash message? When an action was successfully performed, examples:

  • saved a record;
  • started performing something in the background (eg. CSV export);
  • something finished performing in the background (eg. video exported);
  • record was created by someone/something else (eg. a new email arrived).

Flash messages should not be used to show form validation errors, examples are “Password is incorrect” or “Username is too short”. Those are validation errors and should be displayed as close to form (field) as possible.

Using flash messages with Turbo (streams)

The example use of flash messages above work perfectly fine when you are doing a redirect in the controller’s action. Still today, after almost 20 years. But today, you can also render something without redirecting the page, using turbo (streams).

The code needed is almost the same, but requires a bit more set up:

# app/controllers/users_controller.rb
def create
  if @user.save
    respond_to do |format|
      format.html { redirect_to @user, notice: "User Saved" }
      format.turbo_stream { flash.now[:notice] = "User Saved" }
    end
  else
    render :new
  end
end
# app/views/users/create.turbo_stream.erb
<%= turbo_stream.replace "flash" do %>
  <div class="notice">
    <%= flash[:notice] %>
  </div>
<⁠% end %>

Mind the differences:

  • instead of flash[:notice], flash.now[:notice] is needed. This is because there’s no redirect happening. So the flash message needs to be available “now”;
  • the turbo_stream response is needed to tell what to do. In this case replace the #flash div with the the given HTML (there’s probably more in that turbo-stream response).

Flash messages with Turbo Stream broadcasts

If a long-running task has finished in the background, or something else happened the user wants to know about, broadcasting flash messages is a great option.

# app/models/user.rb
after_create_commit -> {
  broadcast_replace_to(
    "flash_messages",
    target: "flash",
    partial: "shared/flash", locals: { flash: "User Saved" }
  )
}
# app/views/shared/_flash.html.erb
<% if flash[:notice] %>
  <div class="notice">
    <%= flash[:notice] %>
  </div>
<⁠% end %>
# app/views/layouts/application.html.erb
<%= turbo_stream_from("flash_messages")

Here, after the user is created, a turbo-stream is broadcasted with the newly created flash-partial (app/views/shared/_flash.html.erb). Replacing the #flash div similar to how it’s done in the controller’s action.

This is a simplified version, as who sees flash messages and when might be a bit more complicated.

More advanced flash messages

Once you know you can use flash messages beyond just simple confirmation messages (“User Saved”, “Signed up Successfully”, and so on), you might want to explore more advanced flash messages.

Take a look at this example from Rails Designer’s Notification Component:

Preview of an advanced notification in Rails

This can be done by passing more data to the flash message, like so:

flash[:alert] = {
  message: "Suspicious Login Attempt",
  description: "We've prevented a login from an unrecognized source.",
  primary_action: {title: "Review Activity", path: "#"},
  secondary_action: {title: "It's Me", path: "#"}
}

In the flash partial (app/views/shared/_flash.html.erb) grab the data, like this:

# app/views/shared/_flash.html.erb
<% if flash[:notice] %>
  <div class="notice">
    <%= flash[:message] %>
    <%= flash[:description] %>
    <%# etc. %>
  </div>
<⁠% end %>

That’s the gist of adding more advanced flash messages. Of course it needs more HTML and CSS. For more examples and inspiration, check out the notifications I created for Rails Designer.

And that is all there is to flash messages in Rails. From really simple ones to quite advanced user-focused notifications that allow actions on them.

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