Rails,respond_to块和|格式|

时间:2015-06-02 15:54:02

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

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正在做什么。不应该 format.htmlformat.json而不是 吗?这两条线实际上在做什么?

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而没有任何逻辑?

3 个答案:

答案 0 :(得分:2)

formatrespond_to yields的局部变量。执行format.html {}时,实际上是在为格式注册回调块。

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

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

format.html块被注册时(如果它只是一个条件语句),你的块内的代码也不会被执行,而是当respond_to完成或者根本不完成时正在使用例如E-Tag缓存。

  

为什么update会在show处理时需要respond_to块   /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假设有一个与控制器同名的资源,并且 auto-magically 填充控制器操作。它还假设app/views/posts/(:action).html.[erb|haml|slim|jbuilder]中有一个视图。

评论大致显示了rails尝试的动作。

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

答案 1 :(得分:1)

嗯,这取决于请求的格式。如果请求要求服务器提供HTML,则会执行format.html阻止,同样,如果请求需要JSON格式,则会执行format.json

Rails将自动(阅读:神奇地)为您处理if (format == html)部分。你所要做的就是填空。同样,您可以从format.xml开始编写XML块。

对于附注,我认为你已经说过了。 update方法不需要respond_to阻止,而show则需要update阻止。原因很简单:show方法可以更新模型,然后将您重定向到某个地方,而/students/1将始终返回一些东西。在您的情况下,/students/1.json将返回您在数据库中创建的第一个学生,并且响应将是HTML,而from nltk.corpus.reader import SyntaxCorpusReader path = '/corpus/wsj' filename = 'wsj1' reader = SyntaxCorpusReader('/corpus/wsj','wsj1') 将返回相同的结果,但这次响应将是JSON。

答案 2 :(得分:0)

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

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

实际上,您的呼叫者应该使用浏览器或者是JSON使用者,发送正确的标头以接收来自样板的响应。