Ajax Spy in Rails

I was playing around with Digg this morning and noticed Digg Spy. At first I thought it was really cool and wondered how they did that. Then I realized it’s just a bit of Ajax and, as anyone who’s read Pragmatic Ajax knows, Ajax is easy! So read on for how I implemented an Ajax spy in Rails and to download the code. The first thing I did was generate a controller and model using Rich White’s excellentAjaxScaffold Generator, called EntriesController and Entry, respectively. This gave me a nice way to create new entries easily. After that I added some basic login/signup support so that the entries could be associated with users. So far, nothing out of the ordinary. Next I created a new controller called SpyController, this is where all of the action happens. I added a basic list method which just returns all of the entries in the DB (sorry, no pagination), this is what we initially call when displaying the page. Then I added an update method which will be called periodically to retrieve new entries, it looks like this:

~~~~ {lang=“ruby”} def update last_update = Time.parse(params[:timestamp]) # locate all of the entries created since the last update @entries = Entry.find(:all, :order => ‘created_at ASC’, :conditions => [ ‘created_at > ?’, last_update.to_s(:db) ]); if !@entries.empty?

render :update do |page|
  for entry in @entries
    page.insert_html(:top, 'spy-list', :partial => 'entry', :object => entry)
    page.visual_effect :highlight, "spy-item-#{entry.id}"

end end ~~~~

At this point I needed some JavaScript to call the update method, so put the following code in application.js:

~~~~ {lang=“ruby”} var updateInterval = 5000; // update every 5 seconds var timestamp = new Date().toUTCString(); var timer;

function go() { timer = setInterval(‘update()’, updateInterval); }

function update() { url = “/spy/update”; new Ajax.Request(url, {

           asynchronous: true,
           method: "get",
           parameters: "timestamp=" + timestamp,
           onSuccess: function(request) {
             timestamp = new Date().toUTCString();

}); } ~~~~

The JavaScript update method calls the SpyController’s update method and passes a timestamp as a parameter (this is the time when the page was loaded, initially, and later the timestamp is updated as new entries are retrieved). To bring it all together I had to add on onload to the list.rhtml view for the SpyController, like this:

~~~~ {lang=“html”} This page updates automatically!

<% if !@entries.empty? %>

<%= render :partial => 'entry', :collection => @entries, :locals => { :hidden => false } %>

<% end %> ~~~~

That’s all there is to it. See, I told you it’s easy! You can download the code from here (Updated for Rails 1.2.3).