我正在阅读Rails入门指南,并对第6.7节感到困惑。在生成一个脚手架之后,我在我的控制器中发现了以下自动生成的块:

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
  end
end

我想了解respond_to块实际上是如何工作的。格式是什么类型的变量?是.html和.json方法的格式对象?的文档

ActionController:: MimeResponds::类方法::respond_to

没有回答问题。


当前回答

我是Ruby的新手,在同样的代码上被卡住了。我纠结的部分比我在这里找到的一些答案更基本。这可能会也可能不会帮助到某些人。

respond_to是超类ActionController上的一个方法。 它需要一个block,就像一个委托。块从do到end,以|格式|作为块的参数。 respond_to执行你的块,将Responder传递到format参数中。

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

Responder不包含.html或.json的方法,但我们无论如何都会调用这些方法!这部分让我大吃一惊。 Ruby有一个叫做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)

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.

附注:在RoR 4.2中respond_to被提取到responders gem中。

其他回答

格式是什么类型的变量?

从java POV来看,format是一种匿名接口的实现。这个接口有一个为每种mime类型命名的方法。当您调用其中一个方法(传递一个块)时,如果rails认为用户需要该内容类型,那么它将调用您的块。

当然,这个匿名胶水对象实际上并没有实现接口——它动态地捕获方法调用,并计算出它所知道的mime类型的名称。

就我个人而言,我认为这看起来很奇怪:你传入的块被执行了。对我来说,传递格式标签和块的散列更有意义。但是——这似乎就是RoR的做法。

响应器注册背后的元编程(参见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)被呈现/执行。我发现这是一个轻量级的方式来创建一个Ajax支持的网站使用jQuery UI弹出窗口。

还有一件事你应该知道- MIME。

如果你需要使用MIME类型,并且默认不支持,你可以在config/initializers/mime_types.rb中注册你自己的处理程序:

演员::类型。“文本/markdown”表单:markdown

我是Ruby的新手,在同样的代码上被卡住了。我纠结的部分比我在这里找到的一些答案更基本。这可能会也可能不会帮助到某些人。

respond_to是超类ActionController上的一个方法。 它需要一个block,就像一个委托。块从do到end,以|格式|作为块的参数。 respond_to执行你的块,将Responder传递到format参数中。

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

Responder不包含.html或.json的方法,但我们无论如何都会调用这些方法!这部分让我大吃一惊。 Ruby有一个叫做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)

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.

附注:在RoR 4.2中respond_to被提取到responders gem中。

这有点过时了,Ryan Bigg在这里做了很好的解释:

http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to

事实上,它可能比你想要的更详细一些。事实证明,在幕后有很多事情要做,包括需要理解MIME类型是如何加载的。