JSON-P output with Rails

    Tim Lucas
    Share

    At the recent Web Directions 06 conference Cameron Adams and Sitepoint’s own Kevin Yank gave a talk on Mashups and APIs, with a mention of JSON-P.

    JSON-P is a method of wrapping the JSON output of your API calls to allow other developers to call your API from within their page, bypassing the browser security mechanism.

    If you peek at the HTML source of Web Connections you’ll notice we’re using JSON-P internally to provide the JS data to do the mapping. In the URL of the JSON-P call we can specify the parameter variable, callback or both, and this will allow others to use our JSON in their own mashups.

    It also integrates nicely with the new Rails REST functionality. For example, Jeremy Keith’s profile page can also be output in JSON format by plugging ‘.js’ on the end. This is nice, but not very useful if you wanted to call it from another page.

    Say Jeremy wanted to mashup this data on his own website to show who he’s friends with. He’d need some kind of JSON-P output so he can access the data from a script tag.

    To add the JSON-P “padding” it’s just a matter of specifying a the “variable” parameter declaring the name of the Javascript variable you want the output assigned to. For this example we’ll specify ‘variable=personJSON’. Notice the difference in output? Now try specifying callback, or both callback and variable.

    So how is this implemented behind the scenes? I have a helper function which I use throughout my application to output JSON:

    
    class ApplicationController < ActionController::Base
      protected
        def render_json(json, options={})
          callback, variable = params[:callback], params[:variable]
          response = begin
            if callback && variable
              "var #{variable} = #{json};n#{callback}(#{variable});"
            elsif variable
              "var #{variable} = #{json};"
            elsif callback
              "#{callback}(#{json});"
            else
              json
            end
          end
          render({:content_type => :js, :text => response}.merge(options))
        end
    end
    

    I can then use this in my PeopleController#show action quite simply:

    
    class PeopleController < ApplicationController
      def show
        @person = Person.find(params[:id])
        respond_to do |format|
          format.js { render_json @person.to_json }
        end
      end
    end

    and that’s all there is to it. JSON-P output with Rails.