How to pass a block to a partial

573 views
Skip to first unread message

Hartmut Bischoff

unread,
Sep 1, 2021, 5:03:19 AM9/1/21
to Roda

Hi,
in rails, a block can be passed to a partial using the :layout directive

How can I pass a block to a partial using the partials-plugin?

```
<% partial( "some_name" ) do %>
{ erb code to be inserted in <%== yield %>  statement in the partial }
<% end %>
```
is not supported, neither is
```
% render( :layout  => '''some_name')  do %>
```

Thanks
Hartmut

Jeremy Evans

unread,
Sep 1, 2021, 11:18:58 AM9/1/21
to ruby...@googlegroups.com
The basic issue with both of these cases is you are using <% and not <%=.  <% will run the Ruby code, but not inject content into the template. However, you cannot use <%=, because <%= partial( "some_name" ) do %> is not valid ERB syntax.  Rails allows it to work by trying to parse the Ruby code with a regular expression, with methods that change the block output temporarily to a different buffer, but Roda does not use such an approach.

There are a few approaches you can use instead:

1) Move the code inside the block to a separate template, and use either

<%= view('content_template', layout: 'layout_template') %>

or the more explicit

<%= render('layout_template'){render('content_template')} %>
 
2) Use the content_for plugin, which does support changing the block output temporarily.  You need to capture the content and emit it as two separate steps:

<% content_for('e') do %>
Content for block
<% end %>
<%= view(layout: 'c', content: content_for('e')) %>

3) Take a similar approach that content_for does, but have it inject content directly into the template, so you don't need the separate step to emit it (the Forme gem's Roda and Sinatra integration works this way). By default, you can inject into the template by writing to @_out_buf.  Maybe something like:

def wrap(&block)
  @_out_buf << "content before block"
  content_for(nil, &block)
  @_out_buf << content_for(nil)
  @_content_for.delete(nil)
  @_out_buf << "content after block"
end

<% wrap do %>
Content for block
<% end %>

4) Separate the header and footer from the layout you want to use into two separate templates, and do:

<%= render('layout_header') %>
Content for block
<%= render('layout_footer') %>

5) Use non-ERB code inside the block:

<%= render('layout_template') do <<-END
Normal Ruby #{'string interpolation'} here
END
end %>

Thanks,
Jeremy

Luke Stutters

unread,
Sep 7, 2021, 5:29:19 PM9/7/21
to Roda
I found the Mastering Roda book helpful when trying to understand the content_for plugin: https://fiachetti.gitlab.io/mastering-roda/
Reply all
Reply to author
Forward
0 new messages