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

没有回答问题。


当前回答

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

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

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

其他回答

这是一段利用Rails helper方法的Ruby代码。如果你还不熟悉block,你会在Ruby中看到很多。

respond_to是一个附加到Controller类(或者更确切地说,它的超类)的Rails助手方法。它引用将发送到视图(将发送到浏览器)的响应。

示例中的块正在格式化数据——通过在块中传入一个“format”参数——当浏览器请求html或json数据时,这些数据将从控制器发送到视图。

如果你在你的本地机器上,你已经设置了Post脚手架,你可以访问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 Jquery or Backbone (or both) to manipulate data and create your own interface. These are called asynchronous UIs and 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.

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内省对象以确定实际的格式。“format”变量的值就是基于这种自省。Rails可以用一点点信息做很多事情。你会惊讶于一个简单的@post或:post能走多远。

例如,如果我有一个_user.html。Erb的部分文件是这样的:

_user.html.erb

<li>    
    <%= link_to user.name, user %>
</li>

然后,在我的索引视图中,这将让Rails知道它需要找到'users'部分,并遍历所有'users'对象:

index.html.erb

 <ul class="users">
   <%= render @users %>     
 </ul>

会让Rails知道它需要找到'user'部分并遍历所有'users'对象:

你可能会发现这篇博客文章很有用: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

“格式”是响应类型。例如,可以是json或html。它是访问者将收到的输出的格式。

响应器注册背后的元编程(参见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”。