为什么在我的 Rails 控制器操作中需要 `render layout: false`?

Sas*_*lla 5 javascript ruby-on-rails ruby-on-rails-4

我使用了在 Rails 中使用 Javascript指南中的remote: true习语:

# new.html.slim
= form_for @thing, remote: true do |f|
  f.text_field :whatever
  f.submit 'Submit'
Run Code Online (Sandbox Code Playgroud)

# thing_controller.rb
layout 'foo'

def create
end
Run Code Online (Sandbox Code Playgroud)

# create.js.erb
alert('foobar')
Run Code Online (Sandbox Code Playgroud)

这失败了,因为由于create.js.erb某种原因在 'foo' 布局内呈现并返回为 html,而不是 javascript,尽管该请求被正确处理为 Javascript:

Processing by ThingsController#create as JS
  Parameters: {"utf8"=>"?", "commit"=>"Submit"}
  Rendered things/create.js.erb (0.6ms)
Run Code Online (Sandbox Code Playgroud)

(无论我respond_to在控制器操作中是否有显式格式块,问题都是一样的。)

如此此处所述,包括render layout: false在控制器操作中解决了问题:

# thing_controller.rb
layout 'foo'

def create
  render layout: false
end
Run Code Online (Sandbox Code Playgroud)

但为什么我需要render layout: false这里?为什么 Rails 在 html 布局中呈现 javascript?我特别困惑,因为我在其他几个地方使用过相同的习语,以前从未遇到过这个问题。

sa7*_*a77 4

Rails 中的动作控制器默认使用 HTML 响应进行响应(除非另有说明)。

layout 'foo'强制使用app/views/layouts/foo.html.slim作为视图文件的模板。因此,与您的操作相关的所有视图thing_controller.rb都会在布局“foo”内呈现,并且使用布局“foo”生成的最终 HTML 和视图文件create.html.slim默认发送回客户端。

如果你想强制返回 js 模板而不是 HTML 文件,你需要在你的操作中显式定义它,如下所示:

# thing_controller.rb
layout 'foo'

def create
  respond_to do |format|
    # use :template if your view file is somewhere else than rails convention
    format.js {
      :template => "somewhere/create.js.erb", 
      :layout => false
    }
  end
end
Run Code Online (Sandbox Code Playgroud)

whererender layout: false强制 Rails 不寻找任何布局文件来包装您的视图文件(即,rails 引擎只处理 create.js.erb“foo”布局上没有定义 HTML 标头的文件)以将其发送回客户端。