Really Simple Blog Badges in Rails 2.0

Posted by paul

When I wanted a quick (and arguably dirty) way to show my current reading list from deadtre.es on this blog, I figured that it was time to play with the JSON support which was baked in Rails 2.0. Wanting to keep things super simple, all I wanted to do was:

  • Create a simple JSON feed I can include via a <script> tag. (I'll write a simple Javascript callback which will insert my reading list into each page. If I decide to make this easier for users I'll put together the usual configuration page where people can play with the look and feel of their badge and get some code to copy and paste.)
  • Keep things RESTful. Each user already has a URL for their bookmarks so I really wanted to avoid to avoid creating new controllers or actions.

Cutting to the chase, this pretty much turns out to be a one-liner in Rails. Here's an example:


class BookmarksController < ApplicationController
  session :off, :only => :index, :if => Proc.new { |request| request.format.json? }
  
  def index
    # fetch bookmarks ...
    respond_to do |format|
      format.json do     
        excluded_book_attrs = [:aws_domain, :id, :created_at, :updated_at]        
        excluded_bookmark_attrs = [:book_id, :id, :updated_at, :user_id]
        render :json => @bookmarks.to_json(:except => excluded_bookmark_attrs, :include => { :book => { :except => excluded_book_attrs }}), :callback => 'show_deadtrees_books'
      end
    end
  end
end

It doesn't get much simpler than that! There are a couple of things worth pointing out:

  • render :json takes care of setting the content type to application/json in the reponse header. Additionally, it wraps the JSON in a call to the method specified by the :callback option. (I should allow users to override this via the querystring to avoid name conflicts in their Javascript or to remove the callback altogether to support use outside of a <script> tag.)
  • You can include Active Record associations when calling to_json using :include
  • You can also control which attributes are serialized (including those on associations) using the :only and :except options.
  • I've disabled sessions for JSON requests to the index action since they're not required and carry a reasonable overhead.

With that in place, all you need to do is implement your Javascript callback (borrow mine if you like) and your blog badge is done!