A Notification System for Ruby on Rails

Published: July 2006


Here’s a nice trick for building a cool notification system that uses the Rails flash array and can be used with Ajax and with normal actions. I’ve used this on two projects and it works just fine (not much that can go wrong anyways).

First, put the following in your layout template:


    <% flash.each do |key,value| -%>
        <h4 id="flash" class='alert <%= key %>'>
            <%= value %>
        </h4>
    <% end -%>

This gives you a dynamic flash thing, so you can use different type of notifications/alerts (i.e. falsh[:error], flash[:critical], etc.)

The styles for the default types error and notice could look something like this (Note: The specialized classes error/notice are named after the flash key. So you can use any key you like and define any layout you need for that):


    h4.alert  {
        font-size: 0.8em;
        font-weight:bold;
        margin:0;    
        padding:5px;
    }

    h4.error  {
        color:#fff;
        background:#c00;
    }
    
    h4.notice {
        color:#060;
        background:#e2f9e3;
    }

Ok, so far so good. This is quite standard. Because typing flash[:blah] = "Something" is boring and after all we want to send a message to the notification system and don’t want to care about arrays, it’s just logical we want to do something like notify :error, "Something went wrong". So let’s define a helper method in our application.rb:


    def notify(type, message)
        flash[type] = message
        logger.error("ERROR: #{message}") 
        if type == :error
    end

Note, this also creates a log entry in case the type is :error. Now that''s it. You have a nice notification system, the CSS class names are named by the notification types and you have easy handler method to fire a note. DRY baby.

Bonus: Fading messages

It’s optional, but sometimes I don’t want the messages to stand in the layout all the time. It was a notification and that’s it. You would not want to have the credits of a movie scrolling on top of the screen all the time, would you? I don’t, so let’s just fade away the message by adding the following snippet to the application.js file:


    /* fade flashes automatically */
    Event.observe(window, 'load', function() { 
        $A(document.getElementsByClassName('alert')).each(function(o) {
            o.opacity = 100.0
            Effect.Fade(o, {duration: 8.0}) });
        });

This requires script.aculo.us, so don’t forget to include it. It softly fades out all flash messages over 8 seconds. You can extend/reduce the duration of course.

Wait, what about those Ajax actions?

Helpers to rescue. Since we have the RJS stuff and helper methods are available to the page object, this is a no-brainer. Let''s define the notify function in application_helper.rb:


        def notify(type, message)
            type = type.to_s  # symbol to string
            page.replace "flash", "<h4 id='flash' class='alert #{type}'>#{message}</h4>"
            page.visual_effect :fade, 'flash', :duration => 8.0
        end
    

Ok, this makes a notify method available so we can send the page object a message:


    render :update do |page|
        # do your stuff here
        page.notify(:notice, "Successfully ... what have you")
    end

The last step is to extend your main flash rendering code to something like this:


    <% if flash.empty? %>
        <h4 id="flash" class="alert" style="display:none"></h4>
    <% else %>
        <% flash.each do |key,value| -%>
            <h4 id="flash" class='alert <%= key %>'>
            <%= value %>
            </h4>
        <% end -%>
    <% end %>

This ensures we always have a element with the ID "flash" rendered, so the notify call can update it.

And that’s that folks. Your basic notification system for your Rails application is ready to roll and keep your precious bodily fluids happy.