x
Your Technical Co-Founder

our clients

partners

engineers

blog

contact

Alex

Pop-Up Notifications in Rails

over 2 years ago by Alex

Popup

A lot of websites nowadays display so-called push notifications on certain events. The best example is Facebook, where your browser, even though idle, is constantly receiving a stream of events from the server: like notifications, new messages, friend requests, etc. There is a surprisingly easy and efficient way to implement this on your website using Pusher, a “hosted API for quickly, easily and securely adding scalable realtime functionality to web and mobile apps”. We found Pusher to be extremely easy to use and well worth the money.

The implementation is done in two parts – the javascript subscription and the event pushing, in Ruby. Let’s proceed with the first part. Open up your layout view file (in our case application.html.haml) and include the javascript library of pusher.

= javascript_include_tag "http://js.pusherapp.com/1.9/pusher.min.js"

Then, considering that you have a current_user function that returns the currently logged in user, you need to subscribe him to his own private channel (denoted by name “user-#{current_user.id}”):

:javascript
  var pusher = new Pusher("#{PUSHER_KEY}");
  var userChannel = pusher.subscribe("private-user-#{current_user.id}");

On the Ruby side, add the pusher gem to the Gemfile (if you’re using bundler):

gem "pusher"

Then, install the gems (bundle install) and add the Pusher credentials to your environment.rb file

PUSHER_APP_ID = "21583"
PUSHER_KEY = '091d8d61ef19881842bf'
PUSHER_SECRET = '7d5e99f780c2d03333ff'

You’ll first need to authenticate access to the private channel we just created. This is done by pusher automatically making a request to /pusher/auth. Thus, you’ll need to create a pusher controller and add the route into routes.rb (post “pusher/auth”).

class PusherController < ApplicationController
  protect_from_forgery :except => :auth # stop rails CSRF protection for this action

  def auth
    Pusher.app_id = PUSHER_APP_ID
    Pusher.key = PUSHER_KEY
    Pusher.secret = PUSHER_SECRET

    if current_user && params[:channel_name] == "private-user-#{current_user.id}"
      response = Pusher[params[:channel_name]].authenticate(params[:socket_id])
      render :json => response
    else
      render :text => "Not authorized", :status => '403'
    end
  end
end

Suppose you have a notification.rb model that is linked to a user (who is supposed to be notified). For the purpose of this example, let’s suppose that the notification model only has 2 fields: user and body. Place the following view code in app/views/notifications/_notification.html.haml:

.notification.unread
  %p
    %span.title To
    = @notification.user.email
  %p
    = @notification.body

Now, whenever you create a notification (in your controllers), add the following code in order to broadcast a message to the private channel of the user. The broadcasted message contains the HTML of the notifications view, which will be made available in JavaScript.

Pusher.app_id = PUSHER_APP_ID
Pusher.key = PUSHER_KEY
Pusher.secret = PUSHER_SECRET

x = render_to_string(:partial => "/views/notifications/notification")
Pusher["private-user-#{@notification.user_id}"].trigger('new-notification', x)

Lastly, you’ll need to use javascript (here with jQuery) in order to bind a function to the new-notification event and show the notification in the client browser.

userChannel.bind('new-notification', function(message) {
  $(".notifications_area").html(message);
});

With a bit of styling you can easily accomplish notifications similar to Facebook, or even extend this to a fully fledged chat system.

However, make sure not to over do it. Otherwise, your users will feel like this (via GraphJam):

Did you like this post? Share it with your friends!