[英]Rails: How does the respond_to block work?
我正在閱讀Rails 入門指南,但對 6.7 節感到困惑。 生成腳手架后,我在控制器中找到以下自動生成的塊:
def index
@posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => @posts }
end
end
我想了解 response_to 塊是如何實際工作的。 什么類型的變量是格式? 是格式對象的 .html 和 .json 方法嗎? 的文檔
ActionController::MimeResponds::ClassMethods::respond_to
不回答問題。
我是 Ruby 的新手,並被困在相同的代碼中。 我掛斷的部分比我在這里找到的一些答案更基本一點。 這可能會或可能不會幫助某人。
respond_to
是超類ActionController
上的一個方法。do
到end
,帶|format|
作為塊的參數。format
參數中。http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html
Responder
不包含.html
或.json
的方法,但我們仍然調用這些方法! 這部分讓我陷入了困境。method_missing
的特性。 如果你調用一個不存在的方法(比如json
或html
),Ruby 會調用method_missing
方法。http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html
Responder
類使用它的method_missing
作為一種注冊。 當我們調用 'json' 時,我們告訴它通過序列化為 json 來響應帶有 .json 擴展名的請求。 我們需要不帶參數調用html
來告訴它以默認方式(使用約定和視圖)處理 .html 請求。可以這樣寫(使用類似 JS 的偽代碼):
// get an instance to a responder from the base class
var format = get_responder()
// register html to render in the default way
// (by way of the views and conventions)
format.register('html')
// register json as well. the argument to .json is the second
// argument to method_missing ('json' is the first), which contains
// optional ways to configure the response. In this case, serialize as json.
format.register('json', renderOptions)
這部分讓我很困惑。 我仍然覺得它不直觀。 Ruby 似乎相當多地使用這種技術。 整個類( responder
)成為方法實現。 為了利用method_missing
,我們需要一個類的實例,所以我們必須傳遞一個回調,他們將類方法對象傳遞到其中。 對於使用類 C 語言編碼 20 年的人來說,這對我來說是非常落后和不直觀的。 不是說不好! 但這是很多具有這種背景的人需要了解的事情,我認為這可能是 OP 所追求的。
ps 請注意,在 RoR 4.2 中respond_to
被提取到響應者gem 中。
這是一個利用 Rails 輔助方法的 Ruby 代碼塊。 如果您還不熟悉塊,您會在 Ruby 中看到很多。
respond_to
是一個附加到 Controller 類(或者更確切地說,它的超類)的 Rails 輔助方法。 它引用了將發送到視圖(將發送到瀏覽器)的響應。
您示例中的塊是格式化數據 - 通過在塊中傳遞一個“格式”參數 - 每當瀏覽器請求 html 或 json 數據時,就會從控制器發送到視圖。
如果您在本地機器上並設置了 Post 腳手架,您可以訪問http://localhost:3000/posts
,您將看到所有 html 格式的帖子。 但是,如果您輸入: http://localhost:3000/posts.json
,那么您將在從服務器發送的 json 對象中看到您的所有帖子。
這對於制作需要從服務器來回傳遞 json 的 javascript 重度應用程序非常方便。 如果您願意,您可以輕松地在 Rails 后端創建一個 json api,並且只傳遞一個視圖 - 就像您的 Post 控制器的索引視圖。 然后你可以使用像Jquery或Backbone (或兩者)這樣的 javascript 庫來操作數據並創建你自己的界面。 這些被稱為異步 UI ,它們變得非常流行(Gmail 就是其中之一)。 它們速度非常快,可為最終用戶提供更類似於桌面的 Web 體驗。 當然,這只是格式化數據的優勢之一。
Rails 3 的寫法是這樣的:
class PostsController < ApplicationController
# GET /posts
# GET /posts.xml
respond_to :html, :xml, :json
def index
@posts = Post.all
respond_with(@posts)
end
#
# All your other REST methods
#
end
通過將respond_to :html, :xml, :json
放在類的頂部,您可以聲明您希望控制器發送到您的視圖的所有格式。
然后,在控制器方法中,您所要做的就是 respond_with(@whatever_object_you_have)
與 Rails 自動生成的相比,它只是簡化了您的代碼。
如果你想知道這個的內部運作......
據我所知,Rails 會內省對象以確定實際的格式。 “格式”變量值基於此內省。 Rails 可以用一點點信息做很多事情。 你會驚訝於一個簡單的 @post 或 :post 能走多遠。
例如,如果我有一個看起來像這樣的 _user.html.erb 部分文件:
_user.html.erb
<li>
<%= link_to user.name, user %>
</li>
然后,僅在我的索引視圖中就可以讓 Rails 知道它需要找到“用戶”部分並遍歷所有“用戶”對象:
index.html.erb
<ul class="users">
<%= render @users %>
</ul>
會讓 Rails 知道它需要找到“用戶”部分並遍歷所有“用戶”對象:
您可能會發現這篇博文很有用: http : //archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with
您還可以仔細閱讀源代碼: https : //github.com/rails/rails
據我所知,respond_to 是一個附加到 ActionController 的方法,所以你可以在每個控制器中使用它,因為它們都繼承自 ActionController。 這是 Rails 的 response_to 方法:
def respond_to(&block)
responder = Responder.new(self)
block.call(responder)
responder.respond
end
你正在傳遞一個block ,就像我在這里展示的那樣:
respond_to <<**BEGINNING OF THE BLOCK**>> do |format|
format.html
format.xml { render :xml => @whatever }
end <<**END OF THE BLOCK**>>
|格式| part 是塊所期望的參數,所以在 respond_to 方法中我們可以使用它。 如何?
好吧,如果您注意到我們在 respond_to 方法中傳遞了帶有前綴 & 的塊,我們這樣做是為了將該塊視為 Proc。 由於參數具有“.xml”、“.html”,我們可以將其用作要調用的方法。
我們在 respond_to 類中所做的基本上是調用方法“.html、.xml、.json”到 Responder 類的實例。
我想了解 response_to 塊是如何實際工作的。 什么類型的變量是格式? 是格式對象的 .html 和 .json 方法嗎?
為了了解什么是format
,您可以先查看respond_to
的源respond_to
,但很快您就會發現真正需要查看的是retrieve_response_from_mimes的代碼。
從這里,您將看到傳遞給respond_to
(在您的代碼中)的塊實際上是通過一個Collector實例調用和傳遞的(在塊中被引用為format
)。 收集器基本上根據 rails 知道的mime 類型生成方法(我相信在 Rails 啟動時)。
所以,是的, .html
和.json
是在 Collector(又名format
)類上定義(在運行時)的方法。
響應者注冊背后的元編程(參見 Parched Squid 的回答)也允許你做這樣的漂亮事情:
def index
@posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => @posts }
format.csv { render :csv => @posts }
format.js
end
end
當您訪問 /posts.csv 時,csv 行將導致在每個帖子上調用 to_csv。 這使得從 Rails 站點將數據導出為 CSV(或任何其他格式)變得容易。
js 行將導致呈現/執行 javascript 文件 /posts.js(或 /posts.js.coffee)。 我發現這是一種使用 jQuery UI 彈出窗口創建支持 Ajax 的站點的輕量級方法。
這有點過時了,Ryan Bigg 在這里做了很好的解釋:
http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to
事實上,它可能比您所尋找的要詳細一些。 事實證明,幕后有很多事情要做,包括需要了解 MIME 類型是如何加載的。
什么類型的變量是格式?
從 Java POV 來看,格式是匿名接口的實現。 這個接口有一個為每種 mime 類型命名的方法。 當您調用這些方法之一(向其傳遞一個塊)時,如果 rails 認為用戶需要該內容類型,那么它就會調用您的塊。
當然,扭曲的是這個匿名膠水對象實際上並沒有實現一個接口——它動態地捕捉方法調用並計算它是否是它知道的 mime 類型的名稱。
就個人而言,我認為它看起來很奇怪:您傳入的塊被執行。 傳遞格式標簽和塊的散列對我來說更有意義。 但是 - 它似乎是在 RoR 中完成的。
“格式”是您的響應類型。 例如,可以是 json 或 html。 這是您的訪問者將收到的輸出格式。
您還應該注意一件事 - MIME。
如果您需要使用 MIME 類型並且默認情況下不支持它,您可以在 config/initializers/mime_types.rb 中注冊您自己的處理程序:
Mime::Type.register "text/markdown", :markdown
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.