Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

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

Trust, but Verify

It's always nice to have test cases that pass, but what about the real world? When I first write my test cases I always like to double-check them to make sure everything is working perfectly. Let's issue a few requests directly to our application using trusty old curl.

Test Viewing a List of Books

Before we start we need to bring up a test server with the following command:

ruby script/server

Then open a second command-line prompt and run the following:

curl http://localhost:3000/books/

The expected response is:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <title>Books</title>
</books>

As you can see, there are no books listed yet.

Test Adding to a List of Books

Next, create a new book:

curl \
  -i \
  -X POST \
  -H 'Content-Type: application/xml' \
  -d '<book><title>a title</title><description>a description</description></book>' \
  http://localhost:3000/books/

The response to this request will include several headers, but the ones we care about are:

HTTP/1.1 201 Created
Location: http://localhost:3000/books/1

Note the URI in the Location header, we'll be using that in a moment.

To make sure the new book is listed in the collection:

curl http://localhost:3000/books/

The expected response is:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <title>Books</title>
  <book>
    <id>1</id>
    <title>a title</title>
    <link href="http://localhost:3000/books/1"/>
  </book>
</books>

Make sure the link's href is the same as the Location header we got from the previous step.

Test Viewing a Book

Follow the Location header from the previous step:

curl http://localhost:3000/books/1

The expected response is:

<?xml version="1.0" encoding="UTF-8"?>
<book>
  <title>a title</title>
  <id type="integer">1</id>
  <description>a description</description>
</book>

Test Changing a Book

Update the book using PUT:

curl \
  -i \
  -X PUT \
  -H 'Content-Type: application/xml' \
  -d '<book><title>a new title</title><description>a new description</description></book>' \
  http://localhost:3000/books/1

This too will return several headers, but at this moment we only care about the first line:

HTTP/1.1 204 No Content

Retrieve the book again to see the changes:

curl http://localhost:3000/books/1

The expected response is:

<?xml version="1.0" encoding="UTF-8"?>
<book>
  <title>a new title</title>
  <id type="integer">1</id>
  <description>a new description</description>
</book>

Test Deleting a Book

We'll delete the book like this:

curl -i -X DELETE http://localhost:3000/books/1

Again, there will be several headers, but the one that tells us the DELETE was successful is the first line:

HTTP/1.1 204 No Content

To verify the book is deleted, perform a GET on the collection:

curl http://localhost:3000/books/

The expected response is:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <title>Books</title>
</books>

The collection contains no books now, just as we would expect.

Only the Beginning

So now we have a simple RESTful Rails application with a full test suite and HTTP method dispatching. We used the HTTP OPTIONS method to identify the methods each resource supports, and we based our test cases around a relatively simple RESTful protocol.

As far as building RESTful Rails applications in Ruby on Rails we're only at the beginning of what is possible. There's an increased interest by the Rails core development team, and David Heinemeier Hansson in particular, in HTTP and the REST architectural style. The RESTful Rails project is off to a good start with per-method dispatching; conditional GET, HTTP Authentication, and more are planned in the near future.

Given the momentum of Ruby on Rails it's a safe bet that in the coming months you'll see more RESTful applications and a better understanding of the HTTP protocol within the community.


Comment on this articleShare your experience in our forums.
(* You must be a member of XML.com to use this feature.)
Comment on this Article


Titles Only Titles Only Newest First
  • AAA 24 hour locksmith Los Angeles CA 1-323-678-2704
    2009-07-02 14:47:31 carpetcare [Reply]

    Locksmiths in Los Angeles CA 1-323-678-2704 Re Keying Locks AND INSTALLATION Brand Name American Locks like:Schlage locks Baldwin locks, Kwikset locks, Mortise locks, Medeco high security locks, Mul-T-lock.
    Locks Installation replacement.
    http://www.locksmithoffice.com
    1-877-364-5264
    Commercial Locksmithing, Specializing in: Banks Office, Apartment Building, New Homes, Condominiums, Retail Stores, Banks Industrial Facilities, Locks and Padlocks, Pharmacies Grocery Stores, Restaurants, Retail stores, Schools, Storage Warehouse.
    Service includes Lockout, locked out need locksmith fast response, Deadbolt Locks repair installation Changed, Installed & Repaired, Re-keys & Master Key Systems, rekey ddors locks, High Security Locks Systems, Home Security Safes, Intercom Systems Repair & Installation, Fire Proof Panic Bars Repaired & Installed, Peephole Installation, High Security Cylinder Changed & Re-Keyed, Closed Curcuit Television CCTV, Card Access Control Systems, Panic Lock Devices, Safes,Windows,Glass Doors & Gates, Padlock, Combination Lock, Electronic Key, Magnetic Keys, Electronic Keypad and Keyless Entry, File Cabinet & Lock Picking.


  • Yea, standard ruby, sorry
    2006-08-01 18:06:17 johnarmstrong [Reply]

    Thats just ruby being wierd and not exposing the joins in the to-xml call. Not a Rails issue.


    And probably something ruby -would- do if i called to_xml properly :)


  • How about joined tables?
    2006-08-01 18:00:53 johnarmstrong [Reply]

    I'd like to see some more info on :has_many and :belongs_to. I hook these up and they are not automagically part of my REST output.


    I think I can expose them manually in the XML but it would be nice to have the view call to .to_xml expose them.




    • How about joined tables?
      2006-08-02 01:28:30 dkubb2 [Reply]

      You wouldn't necessarily want join tables to be automatically dumped via to_xml, simply because for one project a single table join is sufficient, but other projects may need to join several tables to display a resouce. There's not one approach that would satisfy all instances, and to_xml chooses the most efficient approach by default.


      For this example I used to_xml because it was simple, but in real world systems I've worked with a resource is comprised of more than just one model object. For all but the simplest resources I usually pull in several objects for the view.

  • This is an important tutorial
    2006-08-01 17:11:34 johnarmstrong [Reply]

    I can not begin to explain how incredible this tutorial is and how much is has helped me hit the ground running and build truly useful and flexible apps.


    Using these concepts we took was was scheduled to be a 6 month windows MFC based development effort and turned it into a 4 week Flex front-end/RestfulRails backend that blew everyone away.


    Truly incredible.


    Thanks

    • This is an important tutorial
      2006-08-02 01:21:34 dkubb2 [Reply]

      Thanks very much, I'm glad you liked it.


      Since the article was written REST architecture has been fully embraced by the Rails community. Its exciting to see, and I hope its only the beginning.

  • Output problem.
    2006-07-18 12:59:48 Derek Dees [Reply]

    Everything went great until the curl test at the end.


    Then I get:


    D:\tmp\ruby\project_library\app\views\book>curl http://library/books
    <?xml version="1.0" encoding="UTF-8"?>
    <books>
    <title>Books</title>
    <book>
    <id>1</id>
    <title>King in Yellow</title>
    <link href="http://library/books/1"/>
    </book>
    </books>
    Loaded suite D:/tmp/ruby/project_library/public/dispatch.cgi
    Started


    Finished in 0.0 seconds.


    0 tests, 0 assertions, 0 failures, 0 errors



    That's the right info, but the content appended after the </books> tag will cause problems with browsers. I've not been able to find a flag to flip to turn this off. Any suggestions?


    Thanks.




  • Very very very great
    2006-05-30 12:17:52 johnarmstrong [Reply]

    Building some Flex apps and this is exactly what the doctor ordered!


    I need to study the design pattern a bit more to remove the copy/paste voodoo but its quite sexy.


    Thanks!!




  • fixtures :books missing?
    2006-04-27 18:03:33 jabowery [Reply]

    It looks to me like the tutorial is missing the addition of the required:


    fixtures :books


    To:


    test/functional/book_controller_test.rb


    Or am I mistaken?

    • fixtures :books missing?
      2006-04-27 20:33:06 dkubb2 [Reply]

      Its actually at the very bottom of page 3:


      http://www.xml.com/pub/a/2006/04/19/rest-on-rails.html?page=3#collection-fixture

  • Flash integration
    2006-04-22 15:40:07 slipabuck [Reply]

    Hi. I'm building a Flash app that connects to mySQL. I've never done web scripting before, but I picked up enough PHP to do what I need pretty quickly. (Right now, I'm using php.serialize to pass into/out of Flash).


    I recently heard about Rails, and though I'd give it a try. I created the library app per this tutorial and a basic Flash frontend tro test. When I POST to localhost:3000/books with xml.sendAndLoad in Flash, it keeps creating empty records. I tried using CURL as per your tutorial, and it worked fine.



    Here is my log from CURL:


    Processing BookController#collection (for 127.0.0.1 at 2006-04-22 15:22:20) [POST]
    Session ID: 610946147ef5047edb648e39e0f8741a
    Parameters: {"action"=>"collection", "controller"=>"book", "book"=>{"title"=>"losers", "description"=>"never win."}}
    Book Load (0.000000) SELECT * FROM books 
    Book Columns (0.016000) SHOW FIELDS FROM books
    SQL (0.000000) BEGIN
    SQL (0.015000) INSERT INTO books (`title`, `description`) VALUES('losers', 'never win.')
    SQL (0.000000) COMMIT
    Redirected to http://localhost:3000/book/by_id/8
    Completed in 0.04700 (21 reqs/sec) | DB: 0.03100 (65%) | 201 Created [http://localhost/books/]



    And from Flash:


    Processing BookController#collection (for 127.0.0.1 at 2006-04-22 15:27:16) [POST]
    Session ID: 7136b9261bffc44afad273ece4984952
    Parameters: {"action"=>"collection", "<book><title>a title</title><description>a description</description></book>"=>"", "controller"=>"book"}
    Book Load (0.000000) SELECT * FROM books 
    Book Columns (0.031000) SHOW FIELDS FROM books
    SQL (0.000000) BEGIN
    SQL (0.000000) INSERT INTO books (`title`, `description`) VALUES('', NULL)
    SQL (0.000000) COMMIT
    Redirected to http://localhost:3000/book/by_id/9
    Completed in 0.29700 (3 reqs/sec) | DB: 0.03100 (10%) | 201 Created [http://localhost/books/]



    Do you know what would cause the script to recognize the XML from CURL but not from Flash? Any reccommendations? Is it worth doing this in RoR/XML rather than PHP/Serialize?


    Thanks much!

    • Flash integration
      2006-04-22 16:05:36 slipabuck [Reply]

      There's a rule about posting for help with Actionscript - you always find the answer immediately after you ask. I guess putting it in words helps me think of new ways to search for the answer - I don't know.


      Anyway, apparantly there is such an object as XML.contentType in Flash and it need to by "application/xml" for this to work. Sorry for my dumbassity, and I'll try to put together a tutorial after I flesh this out a bit further. =P


      In the mean time, if somebody wants to use this plugin to integrate Rails and Flash, try this actionscript (You need a titlebox and a descriptionbox text field, as well as a sendButton movieclip). Insert this code in the timeline:
      ~~~~~~~~~~~
      stop();
      sendButton.onRelease = function() {
      //send the XML formatted data to the server
      var bookXML:XML = new XML("<book><title>"+titlebox.text+"</title><description>"+descriptionbox.text+"</description></book>");
      trace(bookXML);
      bookXML.contentType="application/xml";
      bookXML.send("http://localhost:3000/books/");
      }


    • Flash integration
      2006-04-22 15:41:30 slipabuck [Reply]

      Sorry for the ridiculous spacing. I didn't realize it would do that. =P

  • test functionals Failure
    2006-04-21 11:49:22 Pedromatic [Reply]

    Is the source code available so I can compare?
    I get the following from rake:


    1) Failure:
    test_routing(BookControllerTest)
    [c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.3.1/lib/active_support/optio
    n_merger.rb:14:in `method_missing'
    ./test/functional/book_controller_test.rb:26:in `test_routing'
    c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.3.1/lib/active_support/core_
    ext/object/misc.rb:28:in `with_options'
    ./test/functional/book_controller_test.rb:25:in `test_routing']:
    The generated path <"/book/collection"> did not match <"/books">