unmagic-component-partial
Named slots for Rails partials rendered as layouts.
Rails partials have one body (the block you pass to render layout:). That's
fine until a component needs content in more than one place — a card with a body
and a footer, a panel with a header actions row and a body. The usual
workarounds (a second partial, a content_for global, a pile of locals carrying
pre-rendered HTML) all leak the component's structure to the caller.
This gem gives a partial named slots, after Dom Christie's Component partials. The caller fills slots inline; the partial reads them back wherever it likes.
Install
# Gemfile
gem "unmagic-component-partial"
The railtie mixes the component_partial helper into ActionView automatically —
no initializer.
Usage
Render the partial as a layout. The block is the body, and is yielded a handle you fill slots on:
<%= render layout: "shared/card", locals: { title: "Profile" } do |card| %>
...the card body...
<% card.content_for :footer do %>
<%= form.submit "Save" %>
<% end %>
<% end %>
Inside the partial, grab a handle with component_partial, render the body with
yield, and read slots back where they belong:
<%# app/views/shared/_card.html.erb %>
<% partial = component_partial %>
<section class="card">
<div class="card__body">
<%= yield partial %>
</div>
<% if partial.content_for(:footer) %>
<footer class="card__footer">
<%= partial.content_for(:footer) %>
</footer>
<% end %>
</section>
The body block and the slot blocks are the same block, so the slots see the caller's locals and helpers exactly as the body does.
API
component_partial— returns a freshPartialbound to the current view.Partial#content_for(name, content = nil, &block):- with a string or block, writes the slot (successive writes to the same
slot append), and returns
nil; - with no content, reads the slot back, or
nilif it was never set.
- with a string or block, writes the slot (successive writes to the same
slot append), and returns
License
MIT