XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Putting REST on Rails
by Dan Kubb | Pages: 1, 2, 3, 4, 5, 6

The RESTful Rails Plugin

The RESTful Rails plugin adds several capabilities to normal Rails controllers that allow them to more effectively use HTTP. The focus of our example will be its most obvious feature, the per-HTTP method dispatching system. With it you will be able to run different code depending on the HTTP request method. A nice extra benefit is that it also takes care of handling the OPTIONS method, which will come in handy in our tests.

To install the plugin, type the following from the command line:


svn co svn://rubyforge.org/var/svn/restful-rails/trunk vendor/plugins/restful-rails

Or if your project is under version control with Subversion already, install it using the Rails plugin system instead:


ruby script/plugin install -x svn://rubyforge.org/var/svn/restful-rails/trunk

Both of these commands will retrieve the latest snapshot of the RESTful Rails plugin and place it in the directory vendor/plugins/restful-rails/.

Now that the plugin is installed, let's create the controller.

The Controller

To create the BookController controller, run the following command:

ruby script/generate controller Book

Test the new controller by running its functional tests:

rake test:functionals

This should pass.

Restful Routes

The BookController controller is going to handle requests for two URIs:

/books/ A collection of books
/books/{id} A book identified by an ID

Let's test that the URIs are being handled properly.

Replace the default test_truth method in test/functional/book_controller_test.rb with the following:

def test_routing
  with_options :controller => 'book' do |test|
    test.assert_routing 'books',   :action => 'collection'
    test.assert_routing 'books/1', :action => 'by_id', :id => '1'
  end
end

This tests that the URIs route to the correct controller and action. Note the use of the new with_options method which saves you some typing by allowing you to specify the default options supplied to all the methods in the block.

rake test:functionals should fail because we haven't set up how URIs are routed to controllers yet.

To set up the routes we need to add a line to config/routes.rb inside the ActionController::Routing::Routes.draw block:

map.connect_resource :book

The connect_resource method is from the RESTful Rails plugin and it will set up routes that match our expected URI structure.

rake test:functionals should now pass.

Now that the routes are set up, we'll move on to the controller.

Making a RESTful Controller

At this point our controller doesn't have any knowledge of the RESTful Rails plugin. To add method dispatching and other features, you need to include RestController::Base at the top of app/controllers/book_controller.rb so it becomes:

class BookController < ApplicationController
  include RestController::Base
end

We're now ready to add the :collection resource to the controller.

The collection Resource

The :collection resource represents a list of books. We want to be able to view the list with the GET method, and add to the list using POST. Let's add a test to test/functional/book_controller_test.rb that ensures these methods are handled:

def test_options_collection
  options :collection
  assert_response HTTP::Status::NO_CONTENT
  assert_no_entity
  assert_allowed_methods :get, :post
end

This tests that when an OPTIONS request is performed on the :collection, it should return a 204 No Content status code. Also the Allow header should identify GET and POST as allowed methods. The options, assert_no_entity and assert_allowed_methods methods are from the RESTful Rails plugin.

rake test:functionals should fail because there is no :collection resource in the controller yet.

First we'll stub out the :collection resource to make the functional tests pass for now. Add the following to app/controllers/book_controller.rb:

resource :collection do |r|
  r.post do
  end
end

rake test:functionals should now pass.

We only specified a stub handler for POST, but didn't say anything about GET. A RESTful Rails resource will handle GET just like a normal Rails action: if you don't use redirect or render, a template with the same name as the resource (if available) will be displayed.

Fixtures

We're almost at the point where we need test data to work with. We'll be reusing the Books fixture we created when testing our model. Simply add the following line above the setup method in test/functional/book_controller_test.rb:

fixtures :books

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow