Create a RESTful REsoure

Problem

You've heard all the buzz about createing RESTful this  and that.There's little doubt that Rails 2.0 heavily favors the REST architectural style and that it will continue to do so.

You're feling a little out of the loop, and what you've heard so far is a tad too academic . As a practical matter, you'd like to create a webaccessible API for one of you models and write a client program to administrer that model remotely. What can resources do for you?

Solution

Let'sforget about REST for a moment and try to solve a problem. Suppose we organize events and we want a web-based interface for creating,reading,updating,and deleting events (affectionately known as CRUD).

The first part of the solution comes in a single command,but what it does can be confusing.The scaffold generator churns out all the CRUD support code for administrering events in a RESTful way . We'll put up event scaffolding in one fell swoop;

ruby script/generate scaffold event name:string description:text capacity:integer price:decimal starts_at:datetime

That single command generates a bunch of code: a model , a controller with no fewer than seven actions,view template files for actions that need them,tests,and even a migration file with the database columns we listed on the commmand line .

 Next , we just need to create the database and apply the migration:

rake db:create

rake db:migrate

That'sall there is to it! Fire up the application, and , lo and behold, we now have a full HTML interface to CRUD (the verb form ) events.

Before we move on to the second part of the solution, let's dive a bit deeper to see what just happened. In some ways , it's just like the old RAils scaffolding, but there's a significant twist. You may have noticed that the following line was added to our config/routes.rb file:

map.resoures :events

That line is the key  ingredient to our RESTful application. It dynamically creates a set of named RESTful routes for accessing our events (called resources ) via URls,The routes map to the seven actions in our controller:index ,show ,new ,create , edit , update, andn destroy .

The best way to see what's going on behind the scenes is to print out all the defined routes by typing this:

rake routes

Let's look at a few just to get a taste of how this works (you'll see more in your output). First , we have routes for dealing with the events collection:

events  GET /events {:controller=>"events", :action=>"index"}

             POST /events {:controller =>"events", "action =>"create"}

The leftmost column gives the name of the route (events),followed by the matching HTTP verb and URL path , and then the action / controller pair that the route ends up invoking. So to list all our events-the index action -we would issue an HTTP GET request to the URL /events, Then ,inside our application, we use the events_url route helper to generate the full URL for listing events ,(Alternatively, you can use the events_path method ot just get the path part of the URL, often referred to as the URI).

Notice that the sam eincoming URL path is mapped to our create action. The only difference is the HTTP verb that's use :GET is a read-only operation that lists the events , and POST is a write operation that createsa new event .

We also have RESTful routes for dealing with a specific member of th events collection:

event  GET /events/:id {:controller=>"events" , :action=>"show"}

          PUT   /events/:id {:controller=> "events", :action =>"update"}

In these cases, the name of the route is singular (event) because it's dealing with one particular event. Again , the URL path is the same for both actions. The HTTP verb is used to disambiguate whether we want to read or update a single event by itsprimary key (the :id route parameter). Inside our application. we use the event_url(@event) route helper. for example , to generate a URL to show our event. Passing @event to the route helper will automatically fill in the :id route parameter with the ID of the event.

So , in a nutshell, the map.resources line generates RESTful routes into our application based on both the incoming URL path and an  HTTP verb . Now browsers generally issue GET and POST requests , leaving the other HTTP verbs to th e academics. So, How do we tell our application that we want ot update an existing event (the PUT verb) or to delete an event (the DELETE verb )? Well , that involves a few more new conventions .

If we have an @event model object (and it;s declared to be a resource), then in our new.html.erb and edit.html.erb forms, we can simply use this :  rest/app/views/events/new.html.erb

<% form_for  @event do |f| -%>

This form will post to our create action because, according to the RESTful routing conventions, the HTTP verb and URL path map to that action.

However, if the event is an existing record that has previously been saved , then Rails knows we're trying to update it . In this case, the form should past to the update action. To do that, the form_for method slaps in a hidden field to simulate a PUT operation. This in turn triggers the proper RESTful route when Rails intercepts the request. It looks something like this in the generated form:

<form action ="/events/1" method ="post">

<input name="_method" type ="hidden" value ="put" />

OK, so at the end of all this , we're still administering events in the browser, just with special URLs , The immediate upshot is we can turn any of our models into resources-events, registrations, users, and so on --and then administer them through a consistent URL scheme .It's just one more example of Rails conventions removing guesswork .

Now let's move on to the second part of the solution . Let's say we'd like to write a client program to administer events remotely. We'll have our client program speak XML back and forth with our Rails application (imagine what that must soudn like !) .To do that, let's turn our attention to the scaffold-generated index action in our EventsController. It has all the familiar stuff, plus a respond_to block :

rest/app/controllers/events_controller.rb

def index

        @events = Event.find(:all)

        respond_to do |format|

          format.html #index.html.erb

         format.xml { render  :xml=> @events }

end

end

The action starts by setting up a collection of events. The respond_to block determines how those events are rendered based on which format the client requests. By default , browsers prefer the HTML format. In that case , the index action renders the index.html.erb  template to generate an HTML response.

However , the index action also responds to requests for events in an XML format. To get the collection of events as XML , we just need our client program to issue a GET request with .xml tacked to

 

 

T

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值