Schienen rendern teilweise mit Block

119

Ich versuche, eine von mir geschriebene HTML-Komponente, die das Panel-Styling bietet, wiederzuverwenden. Etwas wie:

  <div class="v-panel">
    <div class="v-panel-tr"></div>
    <h3>Some Title</h3>
    <div class="v-panel-c">
      .. content goes here
    </div>
    <div class="v-panel-b"><div class="v-panel-br"></div><div class="v-panel-bl"></div></div>
  </div>

Ich sehe also, dass das Rendern einen Block braucht. Ich dachte mir dann könnte ich so etwas machen:

# /shared/_panel.html.erb
<div class="v-panel">
  <div class="v-panel-tr"></div>
  <h3><%= title %></h3>
  <div class="v-panel-c">
    <%= yield %>
  </div>
  <div class="v-panel-b"><div class="v-panel-br"></div><div class="v-panel-bl"></div></div>
</div>

Und ich möchte so etwas tun wie:

#some html view
<%= render :partial => '/shared/panel', :locals =>{:title => "Some Title"} do %>
  <p>Here is some content to be rendered inside the panel</p>
<% end %>

Leider funktioniert dies mit diesem Fehler nicht:

ActionView::TemplateError (/Users/bradrobertson/Repos/VeloUltralite/source/trunk/app/views/sessions/new.html.erb:1: , unexpected tRPAREN

old_output_buffer = output_buffer;;@output_buffer = '';  __in_erb_template=true ; @output_buffer.concat(( render :partial => '/shared/panel', :locals => {:title => "Welcome"} do ).to_s)
on line #1 of app/views/sessions/new.html.erb:
1: <%= render :partial => '/shared/panel', :locals => {:title => "Welcome"} do -%>
...

Also mag es das =offensichtlich nicht mit einem Block, aber wenn ich es entferne, dann gibt es einfach nichts aus.

Weiß jemand, wie man das macht, was ich hier erreichen will? Ich möchte dieses Panel-HTML an vielen Stellen auf meiner Website wiederverwenden.

Brad
quelle
1
Die akzeptierte Antwort ist korrekt, aber da Rails 5.0.0 dies ohne die layoutProblemumgehung möglich ist, sieheguides.rubyonrails.org/…
fabi

Antworten:

208

Während diese beiden obigen Antworten funktionieren (also das Beispiel, auf das Tony sowieso verweist), fand ich in diesem obigen Beitrag die prägnanteste Antwort (Kommentar von Kornelis Sietsma).

Ich denke, render :layoutmacht genau das , wonach ich gesucht habe:

# Some View
<%= render :layout => '/shared/panel', :locals => {:title => 'some title'} do %>
  <p>Here is some content</p>
<% end %>

kombiniert mit:

# /shared/_panel.html.erb
<div class="v-panel">
  <div class="v-panel-tr"></div>
  <h3><%= title -%></h3>
  <div class="v-panel-c">
    <%= yield %>
  </div>
</div>
Brad
quelle
6
In Rails 3.2.2 denke ich, dass Sie <%= %>anstelle von <% %>zB<%= render :layout => '/shared/panel',
Siwei Shen 申思维
Sie haben Recht, dieser Beitrag macht keine Annahmen über die Rails-Version, ich bin sicher, die Leute können das herausfinden.
Brad
wie dieser (löst mein Problem so +1), aber ist das eine gute Praxis? Wird es aus irgendeinem Grund keine Verlangsamung geben? Vielleicht wird die Datenbank aufgrund eines anderen Ertrags früher ausgelöst als angenommen (ich habe jetzt keine Zeit, dies selbst zu untersuchen, frage mich nur)
Äquivalent8
1
Wie können Sie feststellen, ob ein Inhalt erstellt wurde? Im Falle, dass es optional ist.
Vadorequest
3
In Rails 5.0 wurde eine Änderung vorgenommen, sodass dies für alle Partials gilt, nicht nur für Layouts. Sie können die erste Zeile des aufrufenden Codes ändern in:<%= render '/shared/panel', title: 'some title' do %>
Jay Mitchell
27

Hier ist eine Alternative, die auf früheren Antworten basiert.

Erstellen Sie Ihren Teil auf shared/_modal.html.erb:

<div class="ui modal form">
  <i class="close icon"></i>
  <div class="header">
    <%= heading %>
  </div>
  <div class="content">
    <%= capture(&block) %>
  </div>
  <div class="actions">
    <div class="ui negative button">Cancel</div>
    <div class="ui positive button">Ok</div>
  </div>
</div>

Definieren Sie Ihre Methode auf application_helper.rb:

def modal_for(heading, &block)
  render(
    partial: 'shared/modal',
    locals: { heading: heading, block: block }
  )
end

Nennen Sie es aus jeder Sicht:

<%= modal_for('My Title') do |t| %>
  <p>Here is some content to be rendered inside the partial</p>
<% end %>
Rebagliatte
quelle
11

Sie können den Capture-Helfer und sogar Inline im Render-Aufruf verwenden:

<%= render 'my_partial',
           :locals => { :title => "Some Title" },
           :captured => capture { %>
    <p>Here is some content to be rendered inside the partial</p>
<% } %>

und in shared / panel:

<h3><%= title %></h3>
<div class="my-outer-wrapper">
  <%= captured %>
</div>

was produzieren wird:

<h3>Some Title</h3>
<div class="my-outer-wrapper">
  <p>Here is some content to be rendered inside the partial</p>
</div>

Siehe http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html

Noch ein anderer
quelle
1
Das Inline-Muster eignet sich für einen Teil, der mehrere Blöcke benötigt.
Mahemoff
4

Basierend auf der akzeptierten Antwort hat dies für mich mit Rails 4 gut funktioniert.

Wir können ein Panel als solches rendern:

= render_panel('Non Compliance Reports', type: 'primary') do
  %p your content goes here!

Geben Sie hier die Bildbeschreibung ein

Dies erfordert eine Hilfsmethode und eine gemeinsame Ansicht:

Hilfsmethode (ui_helper.rb)

def render_panel(heading, options = {}, &block)
  options.reverse_merge!(type: 'default')
  options[:panel_classes] = ["panel-#{options[:type]}"]

  render layout: '/ui/panel', locals: { heading: heading, options: options } do
    capture(&block)
  end
end

Ansicht (/ui/panel.html.haml)

.panel{ class: options[:panel_classes] }
  .panel-heading= heading
  .panel-body
    = yield
Kris
quelle
Dies funktioniert auch in Rails 5.x, ich musste nur panel.html.hamlzu_panel.html.haml
Kris
1

Ich denke, es wird funktionieren (habe gerade einen schnellen Dirty-Test durchgeführt), wenn Sie es zuerst einer Variablen zuweisen und dann ausgeben.

<% foo = render :partial => '/shared/panel', :locals =>{:title => "Some Title"} do %>
<p>Here is some content to be rendered inside the panel</p>
<% end %>
<%= foo %>
Tesserex
quelle