RESTful Rails for Ajax

April 27, 2007 - 4 minute read -
DOJO-Toolkit JSON ajax

Ruby on Rails 1.2 added full support for building RESTful services to the already nice web page support. REST is a conceptually simple idea, yet incredibly powerful. REST is a Web based API to an application. It builds on the basic building blocks of HTTP: URLs and HTTP Methods (think verbs).

A URL (Uniform Resource Locator) uniquely identifies a resources on the web. HTTP uses the concept of Methods to give context to a request to a URL. Most developers will be familiar with a GET and a POST. These methods are used to get a resource and to modify a resource respectively. But there are other http verbs as well. The two other interesting ones for a REST service are PUT and DELETE. Both of these are pretty self explanatory. PUT creates a resource at the remote location and DELETE removes one.

For Example: GET http://example.com/catalog/item/1

DELETE http://example.com/catalog/item/1

Both of these use the same URL, but the HTTP Method means different things will happen.

Creating A RESTful API with Rails

Rails makes it easy to create a RESTful application. The same controllers can be used to render a web page and to provide a programmatic API to your application.

Rails provides a scaffold_resource generator that creates the skeleton of a resource driven application:

./script/generate scaffold_resource order

This creates Model, View and Controllers just like regular scaffold, but unlike scaffold, it adds some extra functionality.

class OrdersController < ApplicationController
  # GET /orders/1
  # GET /orders/1.xml
  def show
    @order = Order.find(params[:id])<
    respond_to do |format|
      format.html # show.rhtml
      format.xml  { render :xml => @order.to_xml }
    end
  end
end

Now if you request a path ending in .xml it will render the response as an XML document that can be consumed by another program.

Applying REST as an Ajax solution

The great news is that you can use this RESTful API directly as an API to use for building a highly-dynamic Ajax application. (See my post on using Ajax with PHP for an example). But what's even cooler is that you can use the same technique to build a JSON API. JSON is much easier and less resource intensive to consume in an Ajax application than XML.

Changing your controller to support JSON ends up being really easy. All you have to do is add a single line in the respond_to block to support it:

class OrdersController < ApplicationController
  # GET /orders/1
  # GET /orders/1.xml
  # GET /orders/1.js
  def show
    @order = Order.find(params[:id])
    respond_to do |format|
      format.html # show.rhtml
      format.xml  { render :xml => @order.to_xml }
      format.js { render :json => @order.to_json }
    end
  end
end

Just like in the XML example, if you make a request that ends in .js then you will get a response rendered as JSON. Consuming that JSON Service with something like Dojo allows you to easily create a dynamic web application.

dojo.require("dojo.event.*");
dojo.require("dojo.io.*");
dojo.require("dojo.date.*");
dojo.require("dojo.lfx.*");
function getOrder(id) {
    dojo.io.bind({url: "/orders/" + id + ".js", handler: showOrder, mimetype: "text/json"});
}</p>
function showOrder(type, data, evt) {
    dojo.dom.removeChildren(dojo.byId('order'));
    appendOrderPart('order_number', data.attributes.order_number);
    appendOrderPart('time', data.attributes.time);
    dojo.lfx.highlight(dojo.byId('order'), dojo.lfx.Color);
}
function appendOrderPart(id, value) {
    var element = document.createElement("div");
    element.id=id;
    element.innerHTML=value;
    dojo.byId('order').appendChild(element);
}
function init() {
  getOrder(1);
}
dojo.addOnLoad(init);

Conclusion

With a few simple lines of code you can not only render a web page, you can also create an XML API and a JSON API. That's what I call developer friendly!