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

View the List of Books

Even though GET requests are handled automatically we still need to test what will happen when a GET on :collection is done. In our case we want the collection template to be loaded and display a list of all the books in the database in XML format. Let's add a test to test/functional/book_controller_test.rb that ensures this:

def test_get_collection
  get :collection
  assert_response HTTP::Status::OK
  assert_template 'collection'
  assert_equal 'application/xml', @response.content_type

  with_options :tag => 'books' do |test|
    test.assert_tag :children => { :count  => 1, :only => { :tag => 'title', :content => 'Books' } }
    test.assert_tag :children => { :count  => 1, :only => { :tag => 'book',  :content => ''      } }
  end

  with_options :tag => 'book' do |test|
    test.assert_tag :children => { :count  => 1, :only => { :tag => 'id',    :content => books(:http_book).id.to_s } }
    test.assert_tag :children => { :count  => 1, :only => { :tag => 'title', :content => books(:http_book).title   } }
    test.assert_tag :children => { :count  => 1, :only => { :tag => 'link',  :attributes => { :href => @controller.url_for(:action => 'by_id', :id => books(:http_book)) } } }
  end
end

This tests that when a GET :collection is performed, a 200 OK status code should be returned. Also the collection template should be used to render the results in the specified XML format.

rake test:functionals should fail because we haven't created the XML template yet.

Before creating the template we need a way to retrieve a list of all the books from the database. Add one line to the beginning of the :collection resource in app/controllers/book_controller.rb so it becomes:

resource :collection do |r|
  conditions << @books = Book.find(:all)

  r.post do
  end
end

Note that the assignment of @book to conditions is a convention in RESTful Rails. It allows conditional request handling which may be described in more detail at a later time.

Next create the template app/views/book/collection.rxml and make it look like:

xml.instruct!

xml.books do
  xml.title 'Books'

  @books.each do |book|
    xml.book do
      xml.id    book.id
      xml.title book.title
      xml.link  :href => url_for(:only_path => false, :action => 'by_id', :id => book)
    end
  end
end

rake test:functionals should now pass.

Add to the List of Books

So what exactly should we do when handling POST in :collection? Well, its job will be to add a new book to the database as well as redirect the client to the new location of the book. With these expectations we add the following to test/functional/book_controller_test.rb:

def test_post_collection
  new_book = { :title => 'test' }

  post :collection, :book => new_book
  assert_response HTTP::Status::CREATED

  id = Book.maximum('id')
  assert_location :action => 'by_id', :id => id

  book = Book.find(id)
  assert_kind_of Book, book
  assert_equal new_book[:title], book.title
  assert_equal new_book[:description], book.description
end

This tests that when a POST is performed on :collection, a 201 Created status code should be returned. Also the Location header should be set properly and a database check to should be made to ensure the new book was actually created.

rake test:functionals should fail because we haven't added the :collection POST handler yet.

To handle POST requests, we update the r.post handler in app/controllers/book_controller.rb to:

r.post do
  @book = Book.new params[:book]
  if @book.save
    render_post_success :action => 'by_id', :id => @book
  end
end

In this example we use the RESTful Rails render_post_success method which returns a 201 Created status, and sets the Location header to the URI of the new book.

rake test:functionals should now pass.

We're done with the :collection resource now. It handles GET, HEAD, OPTIONS, and POST requests in about nine lines of code. Next we'll move on to the :by_id resource which represents a book using its ID in the database.

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

Next Pagearrow