You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails:使用命名yield渲染Partial时内容无法显示

Rails Partial 命名Yield无法渲染的问题与解决办法

问题描述

尝试通过命名yield在partial中渲染自定义内容,但外部模板中用content_for(:modal_content)定义的内容无法被partial内的yield(:modal_content)捕获,改用无名yield则能正常渲染。

调用partial的模板代码:

<%= render 'shared/remote_modal', modal_title: "bru" do %>
  <%= content_for(:modal_content) do %>
    <%= render @registrations, show_learner: true, show_product: false %> 
  <% end %>
<% end %>

对应的shared/remote_modal partial代码:

<div class="relative px-4 w-full max-w-6xl md:h-auto">
  <!-- Modal content -->
  <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
    <!-- Modal header -->
    <div class="w-full">
      <div class="flex justify-between items-start p-5 rounded-t">
        <div class="w-full-0">
            <h3 class="text-lg font-semibold text-gray-900 dark:text-white">
              <%= modal_title %>
            </h3>
        </div>
        <i class="close-modal fas fa-times text-lg cursor-pointer"></i>
      </div>
    </div>
    <!-- Modal body -->
    <div class="px-6">
      <div class="w-full">
        <%= yield(:modal_content) %> 
      </div>
    </div>
  </div>
</div>

核心原因

Rails的partial不支持直接通过命名yield捕获外部的content_for块。content_for的内容会被存储在全局渲染上下文(对应layout层面的上下文)中,而partial内的yield(:modal_content)只会查找当前partial自身的命名yield定义,无法访问外部模板用content_for设置的内容。无名yield能正常工作是因为它直接接收render块传递的内容,和命名yield的机制完全不同。

解决办法

方法1:局部变量传递内容块

把需要渲染的内容作为局部变量传递给partial,替代命名yield的逻辑:

修改调用模板:

<%= render 'shared/remote_modal', 
           modal_title: "bru",
           modal_content: render(@registrations, show_learner: true, show_product: false) %>

修改partial代码,直接输出局部变量:

<!-- Modal body -->
<div class="px-6">
  <div class="w-full">
    <%= modal_content %> 
  </div>
</div>

如果内容包含复杂ERB逻辑,用capture捕获后传递:

<% modal_content = capture do %>
  <%= render @registrations, show_learner: true, show_product: false %>
  <!-- 其他自定义逻辑 -->
<% end %>

<%= render 'shared/remote_modal', modal_title: "bru", modal_content: modal_content %>

方法2:用无名yield扩展多区域内容

如果partial需要多个自定义区域,可以在render块中传递子块,通过对象方法接收后渲染:

修改调用模板:

<%= render 'shared/remote_modal', modal_title: "bru" do |modal| %>
  <% modal.content do %>
    <%= render @registrations, show_learner: true, show_product: false %>
  <% end %>
<% end %>

修改partial代码,定义接收块的对象:

<% content = nil %>
<% yield OpenStruct.new(
  content: ->(&block) { content = capture(&block) }
) %>

<!-- Modal body -->
<div class="px-6">
  <div class="w-full">
    <%= content %> 
  </div>
</div>

这种方式可扩展支持多个区域(比如modal footer),结构更清晰。

方法3:Rails 7+ 用View Components替代partial(推荐)

Rails 7及以上版本的View Components天然支持多slot(类似命名yield的功能),代码更易维护:

创建组件类app/components/remote_modal_component.rb:

class RemoteModalComponent < ViewComponent::Base
  def initialize(modal_title:)
    @modal_title = modal_title
  end
end

创建组件模板app/components/remote_modal_component.html.erb:

<div class="relative px-4 w-full max-w-6xl md:h-auto">
  <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
    <div class="w-full">
      <div class="flex justify-between items-start p-5 rounded-t">
        <div class="w-full-0">
            <h3 class="text-lg font-semibold text-gray-900 dark:text-white">
              <%= @modal_title %>
            </h3>
        </div>
        <i class="close-modal fas fa-times text-lg cursor-pointer"></i>
      </div>
    </div>
    <div class="px-6">
      <div class="w-full">
        <%= content %>
      </div>
    </div>
  </div>
</div>

调用组件:

<%= render RemoteModalComponent.new(modal_title: "bru") do %>
  <%= render @registrations, show_learner: true, show_product: false %>
<% end %>

如需多slot(比如添加footer),修改组件类:

class RemoteModalComponent < ViewComponent::Base
  renders_one :content
  renders_one :footer
end

模板中添加slot渲染:

<!-- ... 其他代码 ... -->
<div class="px-6">
  <div class="w-full">
    <%= content %>
  </div>
</div>
<% if footer? %>
  <div class="p-6 border-t">
    <%= footer %>
  </div>
<% end %>

调用时传递多slot:

<%= render RemoteModalComponent.new(modal_title: "bru") do |c| %>
  <% c.content do %>
    <%= render @registrations, show_learner: true, show_product: false %>
  <% end %>
  <% c.footer do %>
    <button class="btn">确认</button>
  <% end %>
<% end %>

内容的提问来源于stack exchange,提问作者David Geismar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:05:19