實例公開方法
respond_to(*mimes) 連結
在沒有 Web 服務支援的情況下,收集資料以顯示人員清單的動作可能會如下所示
def index
@people = Person.all
end
該動作隱含回應所有格式,但是也可以明確列舉格式
def index
@people = Person.all
respond_to :html, :js
end
以下是相同的動作,且內建 Web 服務支援
def index
@people = Person.all
respond_to do |format|
format.html
format.js
format.xml { render xml: @people }
end
end
這表示「如果客戶端希望針對此動作回應 HTML 或 JS,只要按照我們之前的做法回應,但是如果客戶端希望回應 XML,則以 XML 格式回傳人員清單給他們。」(Rails
會從客戶端送出的 HTTP Accept 標頭中判斷所需的回應格式。)
假設您有一個動作會新增新的人員,並選擇性地建立其公司(按名稱),如果公司尚未存在,則該動作在沒有 Web 服務的情況下,可能會如下所示
def create
@company = Company.find_or_create_by(name: params[:company][:name])
@person = @company.people.create(params[:person])
redirect_to(person_list_url)
end
以下是相同的動作,且內建 Web 服務支援
def create
company = params[:person].delete(:company)
@company = Company.find_or_create_by(name: company[:name])
@person = @company.people.create(params[:person])
respond_to do |format|
format.html { redirect_to(person_list_url) }
format.js
format.xml { render xml: @person.to_xml(include: @company) }
end
end
如果客戶端希望使用 HTML,我們只會將他們重新導向人員清單。如果他們希望使用 JavaScript,則為 Ajax 要求,而且我們會呈現與此動作關聯的 JavaScript 範本。最後,如果客戶端希望使用 XML,我們會將建立的人員呈現為 XML,但微調一下:我們也會在呈現的 XML 中包含人員的公司,因此您會得到以下結果
<person>
<id>...</id>
...
<company>
<id>...</id>
<name>...</name>
...
</company>
</person>
不過,請注意該動作頂端的額外區塊
company = params[:person].delete(:company)
@company = Company.find_or_create_by(name: company[:name])
這是因為內送的 XML 文件(如果正在處理 Web 服務要求)只能包含一個根節點。因此,我們必須重新排列,讓要求看起來像這樣(URL 編碼)
person[name]=...&person[company][name]=...&...
及這樣(XML 編碼)
<person>
<name>...</name>
<company>
<name>...</name>
</company>
</person>
換句話說,我們讓要求可以在單一實體的人員上執行。然後,在動作中,我們從要求萃取公司資料,找出或建立公司,然後以剩下的資料建立新的人員。
請注意,您可以定義自己的 XML 參數剖析器,這會允許您在單一要求中描述多個實體(即,將它們全部包覆在一個根節點中),但如果您只是順其自然,接受 Rails 的預設值,這樣會容易得多。
如果您需要使用預設情況下不支援的 MIME 類型,您可以如下依照 config/initializers/mime_types.rb
來註冊自己的處理常式。
Mime::Type.register "image/jpeg", :jpg
respond_to
也允許您透過 any
來針對不同格式指定一個共用的區塊
def index
@people = Person.all
respond_to do |format|
format.html
format.any(:xml, :json) { render request.format.to_sym => @people }
end
end
在以上範例中,如果格式為 XML,它會呈現
render xml: @people
或者,如果格式為 JSON
render json: @people
any
也可以在沒有任何引數的情況下使用,在這種情況下,它會用於使用者要求的任何格式
respond_to do |format|
format.html
format.any { redirect_to support_path }
end
格式可以有不同的變體。
要求變體為要求格式的專業化,例如 :tablet
、:phone
或 :desktop
。
我們常常希望針對手機、平板電腦和桌上型電腦瀏覽器呈現不同的 html/json/xml 範本。變體讓這變得容易。
您可以在 before_action
中設定變體
request.variant = :tablet if /iPad/.match?(request.user_agent)
就在動作中回應變體,就像您回應格式一樣
respond_to do |format|
format.html do |variant|
variant.tablet # renders app/views/projects/show.html+tablet.erb
variant.phone { extra_setup; render ... }
variant.none { special_setup } # executed only if there is no variant set
end
end
針對每個格式和變體提供個別範本
app/views/projects/show.html.erb
app/views/projects/show.html+tablet.erb
app/views/projects/show.html+phone.erb
當您不會在格式內分享任何程式碼時,您可以使用內嵌語法來簡化定義變體
respond_to do |format|
format.js { render "trash" }
format.html.phone { redirect_to progress_path }
format.html.none { render "trash" }
end
變數也支援格式常見的任何
/全部
區塊。
對於內嵌與區塊語法都能運作
respond_to do |format|
format.html.any { render html: "any" }
format.html.phone { render html: "phone" }
end
respond_to do |format|
format.html do |variant|
variant.any(:tablet, :phablet){ render html: "any" }
variant.phone { render html: "phone" }
end
end
您也可以設定一個 variant 陣列
request.variant = [:tablet, :phone]
這的運作方式和格式與 MIME 型態協商類似。如果沒有宣告:平板電腦
variant,將會使用:手機
variant
respond_to do |format|
format.html.none
format.html.phone # this gets rendered
end
# File actionpack/lib/action_controller/metal/mime_responds.rb, line 211 def respond_to(*mimes) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? collector = Collector.new(mimes, request.variant) yield collector if block_given? if format = collector.negotiate_format(request) if media_type && media_type != format raise ActionController::RespondToMismatchError end _process_format(format) _set_rendered_content_type(format) unless collector.any_response? response = collector.response response.call if response else raise ActionController::UnknownFormat end end