我正在阅读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

没有回答问题。


当前回答

据我所知,respond_to是一个附加到ActionController的方法,所以你可以在每个单独的控制器中使用它,因为它们都继承自ActionController。下面是Rails的respond_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**>>

|格式|部分是块期望的参数,所以在respond_to方法中我们可以使用它。如何?

好吧,如果你注意到我们在respond_to方法中传递了一个带前缀的&块,我们这样做是为了将该块作为Proc处理。由于参数有“.xml”,“.html”,我们可以使用它们作为要调用的方法。

我们在respond_to类中所做的基本上是调用Responder类实例的方法“.html, .xml, .json”。

其他回答

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

为了理解什么是格式,您可以首先查看respond_to的源代码,但很快您就会发现真正需要查看的是retrieve_response_from_mimes的代码。

从这里,您将看到传递给respond_to(在您的代码中)的块实际上被调用并与Collector的实例一起传递(在块中引用为format)。Collector基本上根据Rails所知道的mime类型生成方法(我相信是在Rails启动时)。

所以,是的,.html和.json是在Collector(又名format)类上定义的方法(在运行时)。

格式是什么类型的变量?

从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弹出窗口。

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

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

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

据我所知,respond_to是一个附加到ActionController的方法,所以你可以在每个单独的控制器中使用它,因为它们都继承自ActionController。下面是Rails的respond_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**>>

|格式|部分是块期望的参数,所以在respond_to方法中我们可以使用它。如何?

好吧,如果你注意到我们在respond_to方法中传递了一个带前缀的&块,我们这样做是为了将该块作为Proc处理。由于参数有“.xml”,“.html”,我们可以使用它们作为要调用的方法。

我们在respond_to类中所做的基本上是调用Responder类实例的方法“.html, .xml, .json”。