How to Integrate Growl Type Notifications Into a Rails App
This tutorial walks through how to easily integrate growl type notifications into a Rails application, including the ability for them to fade out automatically and have images and custom text.
Guide Tasks
  • Read Tutorial

This will be a fun feature to build, in this guide we will integrate growl type notifications into our application. These types of notifications will give the application a professional look and feel and will give a better user experience than the traditional flash notices that ship with Twitter Bootstrap.

In case you haven't really used notifications before, Rails has the ability to post messages to users, such as "You've signed in successfully", or "Post was created", etc. Most applications have notifications that look something like this:

large

There's nothing the matter with these (obviously since it's what the alpha version of the devCamp site used!). However this is a professional Rails developer course so I wanted to integrate a more advanced notification system. We'll be utilizing the gritter gem to enable growl notifications. I think you'll be pleasantly surprised at how easy it is to do along with the clean look and feel that our application will have. To start let's add the gem to the Gemfile:

# Gemfile

gem "gritter", "1.2.0"

After running bundle we only have a few steps we need to take to get the notifications live on the site.

Update the application.js file

This will bring in the jQuery methods needed in order to have the notifications fade out after a timed interval, the order that you place the call to the gritter JS asset is important, so make sure it's called after the jquery import statement:

// app/assets/javascripts/application.js

//= require jquery
//= require bootstrap-sprockets
//= require gritter
//= require jquery_ujs
//= require turbolinks
//= require_tree .

Import the CSS Styles for Growl Notifications

With the JavaScript in place we need to be sure to import the CSS styles that ship with the gem:

/* app/assets/stylesheets/application.css.scss */

@import "bootstrap-sprockets";
@import "bootstrap";
@import "template/chosen.css";
@import "template/fonts.css";
@import "template/gauge.css";
@import "template/graph.css";
@import "template/jquery.fancySelect.css";
@import "template/main.css";
@import "custom/posts.scss";
@import "template/select2.min.css";
@import "custom/table.css";
@import "custom/topics.scss";
@import "custom/devise_styles.css";
@import "gritter";

Integrate into the HTML Code

We already have our notification calls located throughout the controller files, so we don't have to make any changes to them, gritter will render those automatically. We simply need to add a call to the master layout file:

<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html>
<head>
  <title>Dailysmarty</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= render 'shared/header' %>
<%= yield %>

<%= js add_gritter(flash[:notice], title: "DailySmarty Notification", sticky: false) %>

</body>
</html>

The new line <%= js add_gritter(flash[:notice], title: "DailySmarty Notification", sticky: false) %> is using the js method and passing the add_gritter method and a number of parameters. This will render the javascript only when a notice has been called from a controller. Let's go through each of these method arguments to see what they mean:

  • The first argument passed in is the message, this will be dynamic and will print out the message from the controller action.
  • The title is the heading of the notification, this could be dynamic or hard coded.
  • Lastly, the sticky argument let's you choose if you want the notification to stay on the screen until the user navigates to another page or to fade out. I like the idea of the notifications fading out after a few seconds, so I have it set to false.

It's the moment of truth, let's startup the rails server and see what this looks like. If I sign out of the application you'll see that we now have a great looking notification in the right hand corner of the screen:

large

After a few seconds the notification fades out and the screen is back to normal:

large

There are a number of options that gritter offers, you can look into all of them in the gem documentation, a few of the key ones that you may want to incorporate are:

Customizing the timer for the fade

If you alter the add_gritter method like this:

<%= js add_gritter(flash[:notice], title: "DailySmarty Notification", sticky: false, time: 10000) %>

Then the notification will stay up for 10 seconds before fading out.

Adding an Image

You also have the ability to integrate images into the notifications. The gem comes with some built in images, for example, if you want to have images added to the alerts, you could have the add_gritter call look like this:

<%= js add_gritter(flash[:notice], title: "DailySmarty Notification", sticky: false, image: :notice) %>

This will include some icons with each notification. You can see what this looks like for a successful sign in here:

large

Some of the other image options are:
- :success
- :warning
- :notice
- :error
- :progress

You can also pass in a custom image or icons from a URL or the asset pipeline. I personally think the notifications look the best with text only, but feel free to explore all of the different options.

Notification Clean up

So this all looks great, however if we test out going to a page we're not allowed to access, such as editing a post we didn't create nothing comes up. Also, if you try to enter the site with the wrong login credentials you won't get an error notification either. That's not good since those are some pretty important scenarios that users need feedback on. The issue is because our new notifications are only listening for the :notice value in the flash hash. In order to get this working for all the potential flash messages we need to wrap our add_gritter method calls in conditionals that adjust based on the type of alert. Let's update the application layout file like so:

<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html>
<head>
  <title>Dailysmarty</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= render 'shared/header' %>
<%= yield %>

<% if flash[:alert] %>
  <%= js add_gritter(flash[:alert], title: "DailySmarty Alert", sticky: false) %>
<% elsif flash[:error] %>
  <%= js add_gritter(flash[:error], title: "DailySmarty Error", sticky: false) %>
<% else %>
  <%= js add_gritter(flash[:notice], title: "DailySmarty Notification", sticky: false) %>
<% end %>
</body>
</html>

Now if you try to access the site with the wrong login credentials you'll get an appropriate error message.

large

Before ending this lesson let's refactor our template layout file because having a conditional in our master application file will give me a stomach ulcer. We already have an alerts partial where we originally put some of the non stylized notifications. Let's fill that partial file with our conditional:

<!-- app/views/shared/_alerts.html.erb -->

<% if flash[:alert] %>
  <%= js add_gritter(flash[:alert], title: "DailySmarty Alert", sticky: false) %>
<% elsif flash[:error] %>
  <%= js add_gritter(flash[:error], title: "DailySmarty Error", sticky: false) %>
<% else %>
  <%= js add_gritter(flash[:notice], title: "DailySmarty Notification", sticky: false) %>
<% end %>

And now we can simply call the partial from our application layout file:

<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html>
<head>
  <title>Dailysmarty</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= render 'shared/header' %>
<%= yield %>

<%= render 'shared/alerts' %>
</body>
</html>

If you go back to the application you'll see that everything is still working and our code looks much cleaner.

A note on TDD

You may have noticed that we didn't use TDD to integrate the growl notifications. Don't worry, I didn't forget about the test first approach. As you've noticed, whenever we build in a new feature from scratch I start with tests and then implement the functionality. However when you're integrating an outside code library for the first time many times it's more practical to first ensure you know how to integrate the feature. If we started with a test first approach and had issues getting the tests passing, especially with a JavaScript based feature, we wouldn't know if our problem was with improperly configured tests, or with the implementation. Testing JavaScript components in Rails requires a few test suite configuration changes with RSpec/Capybara, so I thought it was best to focus on the feature build, and we can always add tests later if we want to ensure notifications will always work.

Resources