簡體   English   中英

Rails:respond_to 塊是如何工作的?

[英]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上的一個方法。
  • 它需要一個塊,就像一個委托。 塊是從doend ,帶|format| 作為塊的參數。
  • response_to 執行你的塊,將一個 Responder 傳遞到format參數中。

http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html

  • Responder不包含.html.json的方法,但我們仍然調用這些方法! 這部分讓我陷入了困境。
  • Ruby 有一個名為method_missing的特性。 如果你調用一個不存在的方法(比如jsonhtml ),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 控制器的索引視圖。 然后你可以使用像JqueryBackbone (或兩者)這樣的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM