Rails:respond_to块如何工作?

Col*_*ole 206 ruby-on-rails

我正在阅读Rails入门指南并与第6.7节混淆.生成脚手架后,我在控制器中找到以下自动生成的块:

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
  end
end
Run Code Online (Sandbox Code Playgroud)

我想了解respond_to块实际上是如何工作的.什么类型的变量是格式?是格式对象的.html和.json方法吗?该文件ActionController::MimeResponds::ClassMethods::respond_to不回答这个问题.

Cra*_*ste 181

我是Ruby的新手并且遇到了同样的代码.我挂起来的部分比我在这里找到的一些答案更为基础.这可能会或可能不会帮助某人.

  • respond_to是超类的方法ActionController.
  • 它需要一个块,就像一个委托.该块从do直到end,|format|作为块的参数.
  • respond_to执行你的块,将响应者传递给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)
Run Code Online (Sandbox Code Playgroud)

这部分让我感到困惑.我仍觉得它不直观.Ruby似乎使用了这种技术.整个class(responder)成为方法实现.为了利用method_missing,我们需要一个类的实例,所以我们不得不传递一个回调,它们传递类似方法的对象.对于那些用C语言编写了20年的人来说,这对我来说是非常倒退和不直观的.不是很糟糕!但是很多具有这种背景的人需要深入了解,我认为可能是OP所追求的.

ps注意在RoR 4.2中respond_to被提取到responders gem中.

  • 我完全同意,红宝石来源很难阅读。 (4认同)
  • 解释method_missing()作为Responder类中的注册机制的最佳答案!我也*非常*与此代码混淆。 (2认同)

Phi*_*egg 103

这是一个利用Rails辅助方法的Ruby代码块.如果您还不熟悉块,您将在Ruby中看到它们.

respond_to是一个Rails辅助方法,它附加到Controller类(或更确切地说,它的超类).它正在引用将发送到View(将转到浏览器)的响应.

您的示例中的块是格式化数据 - 通过传入块中的"格式"参数 - 只要浏览器发出html或json数据请求,就会从控制器发送到视图.

如果您在本地计算机上并且设置了Post脚手架,则可以转到http://localhost:3000/posts,您将以html格式查看所有帖子.但是,如果你键入: http://localhost:3000/posts.json,那么你将看到从服务器发送的json对象中的所有帖子.

这对于制作需要从服务器来回传递json的javascript繁重的应用程序非常方便.如果你愿意,你可以轻松地在你的rails后端创建一个json api,并且只传递一个视图 - 就像你的Post控制器的索引视图一样.然后你可以使用像JqueryBackbone(或两者)这样的javascript库来操作数据并创建自己的界面.这些被称为异步UI,它们很受欢迎(Gmail就是其中之一).它们非常快,可以让最终用户在网络上获得更像桌面的体验.当然,这只是格式化数据的一个优点.

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
Run Code Online (Sandbox Code Playgroud)

通过放在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>
Run Code Online (Sandbox Code Playgroud)

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

index.html.erb

 <ul class="users">
   <%= render @users %>     
 </ul>
Run Code Online (Sandbox Code Playgroud)

会让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

  • 很好的答案,但没有说明传递给块的格式变量的具体内容.在给出的示例中,有format.html和format.json - 这两个都传递给respond_to然后respond_to决定如何处理它们? (4认同)

Nob*_*ita 10

据我所知,respond_to是一个附加到ActionController的方法,因此您可以在每个控制器中使用它,因为它们都是从ActionController继承的.这是Rails的respond_to方法:

def respond_to(&block)
  responder = Responder.new(self)
  block.call(responder)
  responder.respond
end
Run Code Online (Sandbox Code Playgroud)

你正在传递一个,就像我在这里展示的那样:

respond_to <<**BEGINNING OF THE BLOCK**>> do |format|
  format.html
  format.xml  { render :xml => @whatever }
end <<**END OF THE BLOCK**>>
Run Code Online (Sandbox Code Playgroud)

|格式| part是块期望的参数,因此在respond_to方法中我们可以使用它.怎么样?

好吧,如果你注意到我们在response_to方法中使用带前缀的&传递块,我们这样做是为了将该块视为Proc.由于参数具有".xml",".html",我们可以将其用作要调用的方法.

我们在respond_to类中基本上做的是将方法".html,.xml,.json"调用到Responder类的实例.


rni*_*son 7

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

为了理解它是什么format,你可以先查看源代码respond_to,但很快就会发现你真正需要看的是retrieve_response_from_mimes的代码.

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

所以,是的,.html并且.json是在Collector(aka format)类上定义的(在运行时)方法.