Ruby-on-rails Rails:respond_to 块是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9492362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails: How does the respond_to block work?
提问by Cole
I'm going through the Getting Started with Railsguide and got confused with section 6.7. After generating a scaffold I find the following auto-generated block in my controller:
我正在阅读Rails 入门指南,但对 6.7 节感到困惑。生成脚手架后,我在控制器中找到以下自动生成的块:
def index
@posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => @posts }
end
end
I'd like to understand how the respond_to block actually works. What type of variable is format? Are .html and .json methods of the format object? The documentationfor
我想了解 response_to 块是如何实际工作的。什么类型的变量是格式?是格式对象的 .html 和 .json 方法吗?该文件对
ActionController::MimeResponds::ClassMethods::respond_to
ActionController::MimeResponds::ClassMethods::respond_to
doesn't answer the question.
不回答问题。
采纳答案by Craig Celeste
I am new to Ruby and got stuck at this same code. The parts that I got hung up on were a little more fundamental than some of the answers I found here. This may or may not help someone.
我是 Ruby 的新手,并被困在相同的代码中。我挂断的部分比我在这里找到的一些答案更基本一点。这可能会或可能不会帮助某人。
respond_tois a method on the superclassActionController.- it takes a block, which is like a delegate. The block is from
dountilend, with|format|as an argument to the block. - respond_to executes your block, passing a Responder into the
formatargument.
respond_to是超类上的一个方法ActionController。- 它需要一个块,就像一个委托。块是从
do直到end,|format|作为块的参数。 - response_to 执行你的块,将一个 Responder 传递到
format参数中。
http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html
http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html
- The
Responderdoes NOT contain a method for.htmlor.json, but we call these methods anyways! This part threw me for a loop. - Ruby has a feature called
method_missing. If you call a method that doesn't exist (likejsonorhtml), Ruby calls themethod_missingmethod instead.
- The
Responder不包含.htmlor的方法.json,但我们无论如何都调用这些方法!这部分让我陷入了困境。 - Ruby 有一个名为
method_missing. 如果您调用一个不存在的方法(如json或html),Ruby 会method_missing改为调用该方法。
http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html
http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html
- The
Responderclass uses itsmethod_missingas a kind of registration. When we call 'json', we are telling it to respond to requests with the .json extension by serializing to json. We need to callhtmlwith no arguments to tell it to handle .html requests in the default way (using conventions and views).
- 本
Responder类使用它method_missing作为一种登记。当我们调用 'json' 时,我们告诉它通过序列化为 json 来响应带有 .json 扩展名的请求。我们需要在html不带参数的情况下调用以告诉它以默认方式(使用约定和视图)处理 .html 请求。
It could be written like this (using JS-like pseudocode):
可以这样写(使用类似 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)
This part confused the heck out of me. I still find it unintuitive. Ruby seems to use this technique quite a bit. The entire class (responder) becomes the method implementation. In order to leverage method_missing, we need an instance of the class, so we're obliged to pass a callback into which they pass the method-like object. For someone who has coded in C-like languages for 20 some years, this is very backwards and unintuitive to me. Not that it's bad! But it's something a lot of people with that kind of background need to get their head around, and I think might be what the OP was after.
这部分让我很困惑。我仍然觉得它不直观。Ruby 似乎相当多地使用这种技术。整个类 ( responder) 成为方法实现。为了利用method_missing,我们需要一个类的实例,因此我们必须传递一个回调,它们将类方法对象传递到其中。对于使用类 C 语言编码 20 年的人来说,这对我来说是非常落后和不直观的。不是说不好!但这是很多具有这种背景的人需要了解的事情,我认为这可能是 OP 所追求的。
p.s. note that in RoR 4.2 respond_towas extracted into respondersgem.
ps 请注意,在 RoR 4.2 中respond_to被提取到响应者gem 中。
回答by PhillipKregg
This is a block of Ruby code that takes advantage of a Rails helper method. If you aren't familiar with blocks yet, you will see them a lot in Ruby.
这是一个利用 Rails 辅助方法的 Ruby 代码块。如果您还不熟悉块,您会在 Ruby 中看到很多。
respond_tois a Rails helper method that is attached to the Controller class (or rather, its super class). It is referencing the response that will be sent to the View (which is going to the browser).
respond_to是一个附加到 Controller 类(或者更确切地说,它的超类)的 Rails 辅助方法。它引用将发送到视图(将发送到浏览器)的响应。
The block in your example is formatting data - by passing in a 'format' paramater in the block - to be sent from the controller to the view whenever a browser makes a request for html or json data.
您示例中的块是格式化数据 - 通过在块中传递一个“格式”参数 - 每当浏览器请求 html 或 json 数据时,就会从控制器发送到视图。
If you are on your local machine and you have your Post scaffold set up, you can go to http://localhost:3000/postsand you will see all of your posts in html format. But, if you type in this: http://localhost:3000/posts.json, then you will see all of your posts in a json object sent from the server.
如果您在本地机器上并且设置了 Post scaffold,则可以转到http://localhost:3000/posts,您将看到所有 html 格式的帖子。但是,如果您输入: http://localhost:3000/posts.json,那么您将在从服务器发送的 json 对象中看到您的所有帖子。
This is very handy for making javascript heavy applications that need to pass json back and forth from the server. If you wanted, you could easily create a json api on your rails back-end, and only pass one view - like the index view of your Post controller. Then you could use a javascript library like Jqueryor Backbone(or both) to manipulate data and create your own interface. These are called asynchronous UIsand they are becomming really popular (Gmail is one). They are very fast and give the end-user a more desktop-like experience on the web. Of course, this is just one advantage of formatting your data.
这对于制作需要从服务器来回传递 json 的 javascript 重度应用程序非常方便。如果您愿意,您可以轻松地在 Rails 后端创建一个 json api,并且只传递一个视图 - 就像您的 Post 控制器的索引视图。然后你可以使用像Jquery或Backbone(或两者)这样的 javascript 库来操作数据并创建你自己的界面。这些被称为异步 UI,它们变得非常流行(Gmail 就是其中之一)。它们速度非常快,可为最终用户提供更类似于桌面的 Web 体验。当然,这只是格式化数据的优势之一。
The Rails 3 way of writing this would be this:
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
By putting respond_to :html, :xml, :jsonat the top of the class, you can declare all the formats that you want your controller to send to your views.
通过放置respond_to :html, :xml, :json在类的顶部,您可以声明您希望控制器发送到您的视图的所有格式。
Then, in the controller method, all you have to do is respond_with(@whatever_object_you_have)
然后,在控制器方法中,您所要做的就是 respond_with(@whatever_object_you_have)
It just simplifies your code a little more than what Rails auto-generates.
与 Rails 自动生成的相比,它只是简化了您的代码。
If you want to know about the inner-workings of this...
如果你想知道这个的内部运作......
From what I understand, Rails introspects the objects to determine what the actual format is going to be. The 'format' variables value is based on this introspection. Rails can do a whole lot with a little bit of info. You'd be surprised at how far a simple @post or :post will go.
据我了解,Rails 会内省对象以确定实际的格式。“格式”变量值基于此内省。Rails 可以用一点点信息做很多事情。你会惊讶于一个简单的 @post 或 :post 能走多远。
For example, if I had a _user.html.erb partial file that looked like this:
例如,如果我有一个看起来像这样的 _user.html.erb 部分文件:
_user.html.erb
_user.html.erb
<li>
<%= link_to user.name, user %>
</li>
Then, this alone in my index view would let Rails know that it needed to find the 'users' partial and iterate through all of the 'users' objects:
然后,仅在我的索引视图中就可以让 Rails 知道它需要找到“用户”部分并遍历所有“用户”对象:
index.html.erb
index.html.erb
<ul class="users">
<%= render @users %>
</ul>
would let Rails know that it needed to find the 'user' partial and iterate through all of the 'users' objects:
会让 Rails 知道它需要找到“用户”部分并遍历所有“用户”对象:
You may find this blog post useful: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with
您可能会发现这篇博文很有用:http: //archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with
You can also peruse the source: https://github.com/rails/rails
您还可以仔细阅读源代码:https: //github.com/rails/rails
回答by Nobita
From what I know, respond_to is a method attached to the ActionController, so you can use it in every single controller, because all of them inherits from the ActionController. Here is the Rails respond_to method:
据我所知,respond_to 是一个附加到 ActionController 的方法,所以你可以在每个控制器中使用它,因为它们都继承自 ActionController。这是 Rails 的 response_to 方法:
def respond_to(&block)
responder = Responder.new(self)
block.call(responder)
responder.respond
end
You are passing it a block, like I show here:
你正在传递一个block,就像我在这里展示的那样:
respond_to <<**BEGINNING OF THE BLOCK**>> do |format|
format.html
format.xml { render :xml => @whatever }
end <<**END OF THE BLOCK**>>
The |format|part is the argument that the block is expecting, so inside the respond_to method we can use that. How?
该|格式| part 是块所期望的参数,所以我们可以在 response_to 方法中使用它。如何?
Well, if you notice we pass the block with a prefixed & in the respond_to method, and we do that to treat that block as a Proc. Since the argument has the ".xml", ".html" we can use that as methods to be called.
好吧,如果您注意到我们在 respond_to 方法中传递了带有前缀 & 的块,我们这样做是为了将该块视为 Proc。由于参数具有“.xml”、“.html”,我们可以将其用作要调用的方法。
What we basically do in the respond_to class is call methods ".html, .xml, .json" to an instance of a Responder class.
我们在 respond_to 类中所做的基本上是调用方法“.html、.xml、.json”到 Responder 类的实例。
回答by rnicholson
I'd like to understand how the respond_to block actually works. What type of variable is format? Are .html and .json methods of the format object?
我想了解 response_to 块是如何实际工作的。什么类型的变量是格式?是格式对象的 .html 和 .json 方法吗?
In order to understand what formatis, you could first look at the source for respond_to, but quickly you'll find that what really you need to look at is the code for retrieve_response_from_mimes.
为了了解是什么format,您可以先查看 的源代码respond_to,但很快您就会发现您真正需要查看的是retrieve_response_from_mimes的代码。
From here, you'll see that the block that was passed to respond_to(in your code), is actually called and passed with an instance of Collector(which within the block is referenced as format). Collector basically generates methods (I believe at Rails start-up) based on what mime typesrails knows about.
从这里,您将看到传递给respond_to(在您的代码中)的块实际上是通过一个Collector实例调用和传递的(在块中被引用为format)。收集器基本上根据rails 知道的mime 类型生成方法(我相信在 Rails 启动时)。
So, yes, the .htmland .jsonare methods defined (at runtime) on the Collector (aka format) class.
所以,是的,.html和.json是在 Collector(又名format)类上定义(在运行时)的方法。
回答by Catharz
The meta-programming behind responder registration (see Parched Squid's answer) also allows you to do nifty stuff like this:
响应者注册背后的元编程(参见 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
The csv line will cause to_csv to be called on each post when you visit /posts.csv. This makes it easy to export data as CSV (or any other format) from your rails site.
当您访问 /posts.csv 时,csv 行将导致在每个帖子上调用 to_csv。这使得将数据从 Rails 站点导出为 CSV(或任何其他格式)变得很容易。
The js line will cause a javascript file /posts.js (or /posts.js.coffee) to be rendered/executed. I've found that to be a light-weight way to create an Ajax enabled site using jQuery UI pop-ups.
js 行将导致呈现/执行 javascript 文件 /posts.js(或 /posts.js.coffee)。我发现这是一种使用 jQuery UI 弹出窗口创建支持 Ajax 的站点的轻量级方法。
回答by PaulMurrayCbr
What type of variable is format?
什么类型的变量是格式?
From a java POV, format is an implemtation of an anonymous interface. This interface has one method named for each mime type. When you invoke one of those methods (passing it a block), then if rails feels that the user wants that content type, then it will invoke your block.
从 Java POV 来看,格式是匿名接口的实现。这个接口有一个为每个 mime 类型命名的方法。当您调用这些方法之一(向它传递一个块)时,如果 rails 认为用户需要该内容类型,那么它就会调用您的块。
The twist, of course, is that this anonymous glue object doesn't actually implement an interface - it catches the method calls dynamically and works out if its the name of a mime type that it knows about.
当然,扭曲的是这个匿名胶水对象实际上并没有实现一个接口——它动态地捕获方法调用并计算它是否是它知道的 mime 类型的名称。
Personally, I think it looks weird: the block that you pass in is executed. It would make more sense to me to pass in a hash of format labels and blocks. But - that's how its done in RoR, it seems.
就个人而言,我认为它看起来很奇怪:您传入的块被执行。传递格式标签和块的散列对我来说更有意义。但是 - 它似乎是在 RoR 中完成的。
回答by idStar
This is a little outdated, by Ryan Bigg does a great job explaining this here:
这有点过时了,Ryan Bigg 在这里做了很好的解释:
http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to
http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to
In fact, it might be a bit more detail than you were looking for. As it turns out, there's a lot going on behind the scenes, including a need to understand how the MIME types get loaded.
事实上,它可能比您所寻找的要详细一些。事实证明,幕后有很多事情要做,包括需要了解 MIME 类型是如何加载的。
回答by Rafael Nascimento
"Format" is your response type. Could be json or html, for example. It's the format of the output your visitor will receive.
“格式”是您的响应类型。例如,可以是 json 或 html。这是您的访问者将收到的输出格式。
回答by Rafael Nascimento
There is one more thing you should be aware of - MIME.
您还应该注意一件事 - MIME。
If you need to use a MIME type and it isn't supported by default, you can register your own handlers in config/initializers/mime_types.rb:
如果您需要使用 MIME 类型并且默认情况下不支持它,您可以在 config/initializers/mime_types.rb 中注册您自己的处理程序:
Mime::Type.register "text/markdown", :markdown
Mime::Type.register "text/markdown", :markdown

