Flash Messages (notifications) in Rails Apps
Tags: rails, hotwire
Published: 2024-03-14 18:00:00

_This article was originally published at [Rails Designer](https://railsdesigner.com/flash-in-rails/)._

---

[Flash](https://api.rubyonrails.org/classes/ActionDispatch/Flash.html) has been a feature of Rails since the earliest version, and besides some refinements, the functionality stayed the same.

The 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:

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

```ruby
<div id="flash">
  <⁠% if flash[:notice] %>
    <div class="notice">
      <⁠%= flash[:notice] %>
    </div>
  <⁠% end %>
</div>
```


## When to use 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:

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

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

```ruby
# app/models/user.rb
after_create_commit -> {
  broadcast_replace_to(
    "flash_messages",
    target: "flash",
    partial: "shared/flash", locals: { flash: "User Saved" }
  )
}
```

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

```ruby
# 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](https://railsdesigner.com/components/notifications/):


![Preview of an advanced notification in Rails](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pra0k85ok36uofwccqhx.jpg)

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

```ruby
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 so:

```ruby
# 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](https://railsdesigner.com/components/notifications/).

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