Undistraction
Undistraction

Reputation: 43589

Rendering A Partial / Layout With Multiple Blocks

I have a very simple requirement - I have a layout comprising of a header and body. It is a sub-layout of the page, not for the page itself.

This layout is repeated throughout multiple pages, and it is possible the structure around it will change. So I want to be able to separate the content of the header and the content of the body from the structure that contains it.

My first attempt was to use render a partial as a layout that used named yields to render a header and body:

<header class="Resource-header">
  <%= yield :resource_header %>
</header>
<div class="Resource-body">
  <%= yield :resource_body %>
</div>

Then render it from my templates like this:

<%= render layout: 'admin/resource' do %>

  <% content_for :resource_header do %>
  <% end %>

  <% content_for :resource_body do %>
  <% end %>

<% end %>

However, this renders nothing.

I started playing with the order of things, and discovered that if the content_for blocks are declared before the call to the partial, this approach does work:

<% content_for :resource_header do %>
<% end %>

<% content_for :resource_body do %>
<% end %>

<%= render layout: 'admin/resource' do %><% end %>

However this just feels incredibly hacky. It seems that content_for is scoped globally, and there is no association between the content_for block and the partial rendering.

So what is the correct way for me to achieve this?

Upvotes: 6

Views: 997

Answers (3)

Alex
Alex

Reputation: 2518

Eventhough the question is quite old now, I had a similar issue today. I came up with sth. like this. No gem or custom class required, just some fancy block usage ;)

<!-- app/views/layouts/fancy-blocks.html.erb -->
<%
  body, footer = nil
  yield(
    proc {|&blk| body = capture(&blk) },
    proc {|&blk| footer = capture(&blk) }
  )
%>
<section class="body"><%= body %></section>
<footer><%= footer %></footer>
<!-- app/views/some-other/view.html.erb -->
<%= render 'layout/fancy-blocks' do |body, footer| %>
  <% body.call do %>
    BODY
  <% end %>

  <% footer.call do %>
    FOOTER
  <% end %>
<% end %>

Upvotes: 0

user2954224
user2954224

Reputation: 21

I just happened to have exactly same problem.

Solution is: in your partial layout file 'admin/resource' body:

<header class="Resource-header">
  <%= yield resource, :resource_header %>
</header>
<div class="Resource-body">
  <%= yield resource, :resource_body %>
</div>

in your templates do:

<%= render layout: 'admin/resource' do |resource, section| %>
  <% case section %>
    <% when :resource_header %>
      Resource header shows here.
    <% when :resource_body %>
      Resource body shows here.
  <% end %>

<% end %>

Upvotes: 1

sashaegorov
sashaegorov

Reputation: 1862

Take a look on rails presenters https://www.ruby-toolbox.com/categories/rails_presenters Maybe your solution is cells gem.

Upvotes: 0

Related Questions