通過上一講,我們已經對REST on Rails的基本架構有所瞭解,但是它是如何?根據用戶端的請求類型來返回不同類型的資源表示的呢?這就是我們這一講所要講的,秘密就在於respond_to。
首先讓我們來看看我們在上一講中產生的airports控制器的代碼:
class AirportsController < ApplicationController
def index
@airports = Airport.find :all
respond_to do |format|
format.html # do nothing, allow Rails to render index.rhtml
format.js # do nothing, allow Rails to render index.rjs
format.xml { renderml => @airports.to_xml }
end
end
end
我們以index方法為例,其它方法的實現大同小異。第一行代碼很容易理解,擷取所有的機場資訊,但是接下來的代碼就比較費解了,而這也正是REST on Rails的關鍵所在,那個respond_to是做什麼的呢?
我們知道,在HTTP協議中,用戶端會在他們的HTTP首部包含一些元資訊(meta-information),這些元資訊按照“欄位:值”的方式來組織,HTTP協議預定義了很多標準欄位,其中的一個欄位就是“Accept-type“,它代表發送請求的用戶端能夠支援或者說理解的資源表示類型,如果沒有為這個鍵指定值,服務端會認為用戶端能夠理解標準的HTML文檔,當然,用戶端可以為這個欄位指定任意的符合MIME規範的類型值,假設用戶端設定這個欄位為”Accept-Type: text/xml“,則服務端必須返回資源的XML表示。
所以respond_to事實上就是根據HTTP首部的Accept-Type欄位來決定向用戶端返回那種類型的資源表示,如果不使用respond_to,我們的實現可能會是這個樣子:
class AirportsController < ApplicationController
# Pretend that Rails will call our index action,
# and will pass in the value of the Accept-Type header
def index(client_format)
@airports = Airport.find :all
if client_format == “text/html”
# TO DO: render the default template
elsif client_format == “application/javascript”
# TO DO: return some javascript
elsif client_format == “application/xml” || client_format == “text/xml”
# TO DO: return some XML back the client
# … more elsif statements here for each MIME type you want to support
end
end
end
這很醜陋,不是嗎?但它卻相當直觀,我想respond_to的作者可能最初也是這麼寫的,或者這段代碼至少在他的腦海中閃現過,但立刻就被他否定了,因為它實在是太蹩腳了,所以他對這段代碼進行了重整,於是有了respond_to。
respond_to do |format|
format.html # do nothing, allow Rails to render index.rhtml
format.js # do nothing, allow Rails to render index.rjs
format.xml { renderml => @airports.to_xml }
end
但是Block內的代碼看起來仍然比較古怪,事實上,如果我們理解了respond_to的設計思想,那麼這段代碼看起來就非常理所當然了。
respond_to基於這樣的思想設計的,你不需要知道用戶端的請求到底是那種類型,你只需要告訴Rails你準備支援那些類型的請求,Rails會自動幫你處理剩下的事情。
所以,這裡我們告訴Rails,對於HTML和JS類型的請求,採用預設的實現,而對XML則使用我們在Block內提供的實現。
指南到這裡就結束了,篇幅有限,我們只能對REST的基本概念和它在Rails中的簡單實現做一個基本的介紹,REST on Rails的世界還有更多的東西等著你去探索。
我建議你嘗試動手建立一個Rails應用,然後試試scaffold_resource產生器,閱讀並試著理解產生的程式碼,然後嘗試修改view和controller,事實上,比你想象的要簡單的多,不是嗎?