Rails中的嵌套布局

时间:2013-12-09 21:15:56

标签: ruby-on-rails layout nested

我无法找到办法执行以下操作:

让我们在我的application.html.erb中说我有以下

<div id="one" >
    <%= yield %>
</div>

然后我想要另一个布局文件asdf.html.erb

<div id="two">
    <%= yield %>
</div>

我希望最终输出为

<div id="one>
   <div id="two">
      <%= yield %>
   </div>
</div>

有可能吗?感谢。

6 个答案:

答案 0 :(得分:14)

我发现到目前为止最干净的解决方案来自此代表:https://github.com/rwz/nestive

我不想要整个宝石。如果你像我一样,这就是我实现我想要的方式:

# application_helper.rb

  # From https://github.com/rwz/nestive/blob/master/lib/nestive/layout_helper.rb
  def extends(layout, &block)
    # Make sure it's a string
    layout = layout.to_s

    # If there's no directory component, presume a plain layout name
    layout = "layouts/#{layout}" unless layout.include?('/')

    # Capture the content to be placed inside the extended layout
    @view_flow.get(:layout).replace capture(&block)

    render file: layout
  end

然后你保持/layouts/application.html.erb不变!

您可以创建其他布局。就我而言/layouts/public.html.erb/layouts/devise.html.erb

# public.html.erb
<%= extends :application do %>
  <%= render 'partials/navbar' %>
  <div class="container margin-top">
    <%= yield %>
  </div>
<% end %>

# devise.html.erb
<%= extends :public do %>
  <div class="col-sm-6 col-sm-offset-3">
    <%= yield %>
  </div>
<% end %>

像魅力一样!我还在微笑,我终于找到了一个干净的解决方案。

答案 1 :(得分:7)

默认情况下,application.html.erb是您的布局。您可以通过从应用程序布局中将其调用为部分来呈现默认子布局:

# app/views/layouts/application.html.erb
<div id="one" >
    <%= render "layouts/asdf" %>
</div>

# app/views/layouts/_asdf.html.erb
<div id="two">
    <%= yield %>
</div>

这将输出以下内容:

<div id="one>
   <div id="two">
      <%= yield %>
   </div>
</div>

或者,如果您希望逐个控制地有条件地渲染布局,则应考虑使用nested layouts。来自文档:

  

在NewsController生成的页面上,您想隐藏顶层菜单并添加右侧菜单:

# app/views/layouts/news.html.erb
<% content_for :stylesheets do %>
  #top_menu {display: none}
  #right_menu {float: right; background-color: yellow; color: black}
<% end %>
<% content_for :content do %>
  <div id="right_menu">Right menu items here</div>
  <%= content_for?(:news_content) ? yield(:news_content) : yield %>
<% end %>
<%= render template: "layouts/application" %>
  

新闻视图将使用新布局,隐藏顶部菜单并在“内容”div中添加新的右侧菜单。

答案 2 :(得分:4)

asdf.html.erb重命名为_asdf.html.erb并将application.html.erb重写为:

<div id="one">
  <%= render 'asdf' %>
</div>

有关此处部分内容的更多信息:http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials

答案 3 :(得分:1)

您还可以执行以下操作以有条件地呈现子布局:

# app/views/layouts/application.html.erb
<%= controller.controller_name.include?("foo") ? render("layouts/foo") : yield %>

# app/views/layouts/_foo.html.erb
<div class="bar">
    <%= yield %>
</div>

对于只有一个子布局的场景,我发现这比Rails guide中概述的嵌套布局方法更可取,因为执行不必从子布局转到主布局,然后回到子布局。相反,它更自然地流动,从主布局开始,继续到子布局,然后在视图结束。

答案 4 :(得分:0)

如果你正在寻找一个干净的解决方案,它不会将application.html.erb与其继承元素耦合,那么gem nestive(正如另一个所指出的那样,但它似乎不适用于Rails 5.但这是另一种方法:https://mattbrictson.com/easier-nested-layouts-in-rails

# Place this in app/helpers/layouts_helper.rb
module LayoutsHelper
  def parent_layout(layout)
    @view_flow.set(:layout, output_buffer)
    output = render(:file => "layouts/#{layout}")
    self.output_buffer = ActionView::OutputBuffer.new(output)
  end
end

然后asdf.html.erb变为

<div id="two">
    <%= yield %>
</div>
<% parent_layout 'application' %>

请注意,这依赖于Rails内部,并且可能会在将来的版本中停止工作。这不太可能很快发生,因为它至少已经工作了3年(根据链接博客文章的日期)。

答案 5 :(得分:0)

我多年来一直使用这种方法:

# app/helpers/layout_helper.rb
module LayoutHelper
  def inside_layout(layout = 'application', &block)
    render inline: capture(&block), layout: "layouts/#{layout}"
  end
end

那么你的 asdf 布局将是:

# app/views/layouts/asdf.html.erb
<%= inside_layout do %>
  <div id="two">
    <%= yield %>
  </div>
<% end %>