Rails Flash what you need to know

How to use and customize Rails Flash messages and types

Stéphane Paquet
5 min readFeb 22, 2022
Photo by Joel Muniz on Unsplash

For this project we will need the following ingredients:

  1. A new Rails 7 project rails new flash_msg --css=tailwind --javascript=esbuild
  2. Your favorite IDE
  3. Scaffold Post using the following cmd: rails g scaffold Post title:string msg:text
  4. Update the root so that we default to posts#index by adding the following line to the routes.rb file root "posts#index"
  5. Run the migration to create the table (this project is using SQLite, but you can change to PostgreSQL or MySQL — if so, do not forget to update the Gemfile or add — database when creating the project at step 1)

or just get the source from github: https://github.com/spaquet/rails-flash-msg

Let’s make it look better as the out of the box configuration is placing all the elements on the upper left side of the screen.

Improve the general look & feel:

Application.html.erb

<div class="max-w-6xl pt-4 mx-auto">
<%= yield %>
</div>

This will horizontally and equally pad the content and add some padding at the very top to avoid colliding with the browser navigation bar.

Application.tailwind.css

Let’s take care of the form fields. As this is a component that will be used everywhere in the app, let’s add the CSS to the application.tailwind.css and create a class to define a generic style for all the fields.

@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components { .form-field {
@apply border border-slate-300 focus:border-slate-900 p-2;
}
}

We now just have to edit the partial used by the form _form.html.erb located in the app/views/posts folder

Tada! Our form is now looking a bit better. At least, we can see where the fields are:

Let’s now focus our attention on the flash messages.

Flash, Flash and more Flash

If you open the index.html.erb or the show.html.erb file inside the app/views/posts directory you will notice that their very first line contains the following piece of code:

<p style="color: green"><%= notice %></p>

Now this is a bit reductive as it only displays flash messages of type notice. But before that let’s check how this message is triggered.

Open the posts_controller.rb under the app/views/posts folder and go to either the create or update method.

format.html { redirect_to post_url(@post), notice: "Post was successfully created." }

As you can see the redirect_to method takes 2 arguments. One is the location to redirect to and the second one is the flash message. In this case the flash message is of type notice and the message itself if “Post was successfully created”

Flash messages are stored as hash, meaning that they can be identified as key, value couples.

Given this information we can write a more generic flash partial that will handle more cases.

<% if flash.any? %>
<% flash.each do |type, msg| %>
<div class="py-2 px-4 font-bold msg-<%= type %>">
<%= msg %>
</div>
<% end %>
<% end %>

Remove the <p style="color: green"><%= notice %></p> from the index and show (.html.erb) files as we are going to call our partial from the application.html.erb file.

<body>
<div class="max-w-6xl pt-4 mx-auto">
<%= render "layouts/flash" %>
<%= yield %>
</div>
</body>

and of course we need to add a few CSS in application.tailwind.css

.msg-notice {
@apply bg-green-300 text-green-900;
}
.msg-alert {
@apply bg-red-300 text-red-900;
}

Adding more flash types

We now have a working flash solution to display notice and alert types. Let’s say we want to add an info type of message. Well, as Flash is a Hash our first intuition should be that we can add them straight out when calling the flash command, something like flash[:custom_type]="Message to be displayed" Well, yes and no. Doing so will work in many cases, but not when using the redirect_to method as according to: https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/flash.rb

Example:

Let’s add a custom css style in the application.tailwind.css file

.msg-custom {
@apply bg-yellow-300 text-yellow-900;
}

and then modify the create method of the posts_controller.rb file as follow:

# POST /posts or /posts.json
def create
@post = Post.new(post_params)
respond_to do |format|
flash[:custom]= "Post was successfully created / Custom message"
if @post.save
format.html { redirect_to post_url(@post), success: "Post was successfully created." }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

What we will have is the text “Post was successfully created / Custom message” in yellow on a lighter yellow background once we create a new Post, but the text for the success type will never show up as the redirect_to method is not allowing this type.

How can we fix this?

According to the comment in https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/flash.rb we need to declare our custom styles by adding them to the list in the ApplicationController.

class ApplicationController < ActionController::Base
add_flash_types :success, :warning, :info
end

In the above code we are defining 3 new types: success, warning and info that can be used in the redirect_to method.

The following code will now be working as expected (after defining the associated CSS style in the application.tailwind.css file)

# POST /posts or /posts.json
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to post_url(@post), success: "Post was successfully created." }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

What about render?

When calling render we are staying on the same page. So if we have to display an error in a flash message by calling flash[:error]=”Error message”. Since there is no redirection the error message will not be displayed…

This is why the .now mehod exists and calling flash.now[:error]=”Error message” is there to fix this. Using .now place the message in the flash hash and removes it to avoid displaying the message twice.

Keep in mind that not displaying the page called in the redirect_to will keep the flash message in the hash. This potentially means that your users can receive inconsistent flash messages.

coming up next: using turbo and stimulus to improve the flash message display.

--

--