Custom Rails flash notification with Toastr

By default, Rails give us some plain flash notification. I’m gonna show you how to get from this:

my alternate text

To this:

my alternate text

Pretty cool uh?.

Lets begin

1.Creating the project

The first thing we need is to create the project, I’m gonna upload this code to Heroku so I need my database to be Postgresql, the flag -M is to not have mailers files and -T is because we don’t need tests for this app:

rails new custom_flash_notifications -d=postgresql -M -T


2.Generating all the MVC part

To keep this simple we are gonna create the model Person with a name and an age, all this is gonna be created with the magic of scaffold:

rails g scaffold Person name age

Then, create the database and do the migrations:

rake db:create db:migrate

Finally, and before running the app, change the routes:

# routes.rb

Rails.application.routes.draw do
  resources :people
  root 'people#index'
end

Now lets create the first person of the list to see the rails default notification: my alternate text Time to do some magic.

3.Adding Toastr to our project

Go to Toastr and download the .zip file or .tar.gz depending of your OS. Once that you have It, open It and copy toastr.min.js and toastr.js.map into app/assets/javascript. Now, if you don’t want to modify the style of the notifications copy toastr.min.css intoapp/assets/stylesheets otherwise use the toastr.css and custom the toasts as you wish. Time to define our alerts

4.Creating custom flash types

With this you can define all the alerts you want:

add_flash_types :success, :danger, :info

Add that line in your application_controller

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  add_flash_types :success, :danger, :info
end

Now, go to app/views/layouts/application.html.erb and before the tag <%= yield %> add <%= render :partial => 'flash_messages', :flash => flash %> like this:

# app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>CustomFlashNotifications</title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
  <body>
    <%= render :partial => 'flash_messages', :flash => flash %>
    <%= yield %>
  </body>
</html>

Lets add that partial. Create a file with the name _flash_messages.html.erb in a new folder called app/views/application/ and add the following code

# app/views/application/_flash_messages.html.erb

<% if flash.present? %>
  <div id='flash'>
   <script>
     <% if flash[:success] %>
       var $toastContent = $('<span><%= flash[:success] %></span>');
       toastr.success($toastContent)
     <% end %>
     <% if flash[:info] %>
       var $toastContent = $('<span><%= flash[:info] %></span>');
       toastr.info($toastContent)
     <% end %>
     <% if flash[:danger] %>
       var $toastContent = $('<span><%= flash[:danger] %></span>');
       toastr.error($toastContent)
     <% end %>
   </script>
  </div>
<% end %>

Each flash here is one of the flash that we created before.

5.Modifying the controller

Finally, go to app/controllers/people_controller.rb and update your alerts for the ones that we created like this:

# app/controllers/people_controller.rb

...
#Changing notice for success
def create
  @person = Person.new(person_params)
  respond_to do |format|
    if @person.save
      format.html { redirect_to @person, success: 'Person was successfully created.' }
      format.json { render :show, status: :created, location: @person }
    else
      format.html { render :new }
      format.json { render json: @person.errors, status: :unprocessable_entity }
    end
  end
end
#Changing notice for info
def update
  respond_to do |format|
    if @person.update(person_params)
      format.html { redirect_to @person, info: 'Person was successfully updated.' }
      format.json { render :show, status: :ok, location: @person }
    else
      format.html { render :edit }
      format.json { render json: @person.errors, status: :unprocessable_entity }
    end
  end
end
#Changing notice for danger
def destroy
  @person.destroy
  respond_to do |format|
    format.html { redirect_to people_url, danger: 'Person was successfully destroyed.' }
    format.json { head :no_content }
  end
end

...

6.Results

Now, lets try what we did.
Success: my alternate text

Info: my alternate text

Danger: my alternate text

Awesome!.

Here is the code: GitHub