【问题标题】:Rails, respond_to blocks and |format|Rails、respond_to 块和 |format|
【发布时间】:2015-08-16 12:40:14
【问题描述】:

Rails scaffold 生成以下内容:

respond_to do |format|
  if @student.save
    format.html { redirect_to @student, notice => 'Student was successfully created.' }
    format.json { render :show, status: :created, location: @student }
  else
    format.html { render :new }
    format.json { render json: @student.errors, status: :unprocessable_entity }
  end
end

阅读this 后,我了解respond_to 是如何工作的(有点),但我不明白format 在做什么。不应该是 either format.htmlformat.json 而不是 both?这两行实际上在做什么?

format.html { render :new }
format.json { render json: @student.errors, status: :unprocessable_entity }

里面有隐含的if吗?是不是有点像

if (format == html) {}
if (format == json) {}

旁注:为什么update 需要respond_to 块,而show 将处理/students/1.json/students/1 根本没有任何逻辑?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4


    【解决方案1】:

    format 是一个局部变量 respond_to yields。当您执行format.html {} 时,您实际上是在为一种格式注册一个回调块。

    Rails 会检查已注册的格式并尝试找到与MIME type in the request 兼容的格式。如果没有处理程序,它将引发错误。

    这可以解释为在case 语句(Ruby 等效于 switch 语句)之上使用语法糖。但是这个类比并不完全准确,因为 Rails 在匹配请求类型方面做了一些工作。

    此外,当format.html 块被注册时(就像它只是一个条件语句一样),你的块内的代码也不会执行,而是在respond_to 完成时执行,或者如果你正在使用,则根本不执行电子标签缓存。

    为什么 update 需要 respond_to 块,而 show 会处理 /students/1.json 或 /students/1 根本没有任何逻辑?

    Rails 通过使用约定优于配置的方法并猜测动作的意图来处理许多动作。

    def PostsController < ApplicationController
       def index
         # rails auto-magically fills in the controller with something 
         # like this
         @posts = Post.all
         respond_to do |format|
           format.html { render :index }
           format.json { render json: @posts }
         end 
       end
    
       def show
         # convention over configuration is awesome!
         @post = Post.find(params[:id])
         respond_to do |format|
           format.html { render :show }
           format.json { render json: @post }
         end
       end
    
       def new 
         @post = Post.new
         render :new
       end
    
       def edit 
         @post = Post.find(params[:id])
         render :edit
       end   
    end
    

    Rails 假定存在与控制器同名的资源,并且自动神奇地 填充控制器动作。它还假设app/views/posts/(:action).html.[erb|haml|slim|jbuilder] 中有一个视图。这被称为implicit rendering

    cmets 大致显示了 rails 尝试的操作。

    它不填充对数据进行操作(创建、更新、销毁)的操作,因为实际实现可能会有很大差异,而且很难做出有用的猜测。

    【讨论】:

    • 非常有帮助。谢谢你。最后澄清一下,format.htmlformat.json 可以大致理解为 if 语句。 if(json)if(html) 或案例陈述,或其他。我敢肯定,一旦我把约定搞定,我会欣赏它的优雅,但现在它很混乱。
    • 是的,它们可以被解读为if 语句,如果请求类型是html,则执行format.html 块。但我认为更好的比喻是将它们想象成 jQuery 中的成功/失败 ajax 回调。如果请求匹配,它们是要执行的代码块 - 但responds_to 决定何时何地。
    • 听起来有点像头​​发分裂,但它更容易理解密集的语法。 format.html 是一种方法,您将块(匿名函数)作为参数传递给它。它根本不是一个条件,而是注册一个回调。
    • 整个 respond_to 块令人费解。但我认为我的特定问题已得到彻底解答。
    【解决方案2】:

    嗯,你可以用 'foo' 或 'banana' 或任何你想要的东西来替换 'format'。在这种情况下,它只是变量名称,因为 response_to 发送到您的块的变量正在传递传入 http 请求的 Accept 标头所请求的格式。

    有时您会在日志中看到 422“不可接受”错误,因为您收到带有 Accept 标头的请求,但该请求并未请求您的应用知道的 mime 类型。

    事实上,您的调用者应该使用浏览器或作为 JSON 消费者发送正确的标头以接收来自样板的响应。

    【讨论】:

      【解决方案3】:

      嗯,这取决于请求的格式。如果请求需要来自服务器的 HTML,则将执行 format.html 块,同样,如果请求需要 JSON 格式,则将执行 format.json

      Rails 会自动(读作:神奇地)为您处理 if (format == html) 部分。您所要做的就是填写空白。同样的方法,您可以为 XML 编写一个以 format.xml 开头的块。

      关于旁注,我想你已经说过了。 update 方法不需要 respond_to 块,而 show 需要。原因很简单:update 方法是用来更新模型,然后将你重定向到某个地方,而show 总是会给你返回一些东西。在您的情况下,/students/1 将返回您在数据库中创建的第一个学生,响应将是 HTML,而 /students/1.json 将返回相同的结果,但这次响应将是 JSON。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-11
        • 2018-08-28
        • 1970-01-01
        • 2017-11-08
        • 1970-01-01
        • 1970-01-01
        • 2015-11-24
        • 1970-01-01
        相关资源
        最近更新 更多