Skip to content

Fix stale content cache when slots are accessed before render_in#2603

Merged
joelhawksley merged 4 commits intoViewComponent:mainfrom
armstrjare:fix/stale-content-cache-on-slot-access
Apr 14, 2026
Merged

Fix stale content cache when slots are accessed before render_in#2603
joelhawksley merged 4 commits intoViewComponent:mainfrom
armstrjare:fix/stale-content-cache-on-slot-access

Conversation

@armstrjare
Copy link
Copy Markdown
Contributor

Problem

content caches its result in @__vc_content after first evaluation. render_in resets @__vc_content_evaluated to false, but doesn't clear the cached @__vc_content value. This means if content was evaluated before render_in, the stale cached result is returned on every subsequent call — the render block passed when rendering the component is never evaluated.

This is easy to trigger in practice because __vc_get_slot eagerly calls content to ensure content-defined slots are loaded:

# slotable.rb
def __vc_get_slot(slot_name)
  content unless defined?(@__vc_content_evaluated) && @__vc_content_evaluated
  ...
end

So any slot predicate (e.g. column?, header?) called before render_in poisons the cache. This comes up when building a component's structure first (configuring slots in a helper or setup block) and rendering it later with a content block:

# helper.rb
def my_table
  Ui::Table.new.tap do |table|
    table.with_column "Name" %>
    table.with_column :options unless table.column?(:options) # triggers content evaluation
  end
end
<%# template.html.erb %>
<%= render my_table do %>
  <%= render partial: "row" %>  <%# silently ignored %>
<% end %>

Fix

Clear @__vc_content in render_in alongside the existing @__vc_content_evaluated reset, so the cache is fully invalidated on each render.

Adds a regression test that accesses a slot predicate before render_in and asserts the content block is rendered.

armstrjare and others added 4 commits April 14, 2026 13:37
render_in resets @__vc_content_evaluated but does not clear the cached
@__vc_content. If content was evaluated before render_in (e.g. via a
slot predicate calling __vc_get_slot), the stale nil is returned on
every subsequent call and the render block is silently ignored.

Clear @__vc_content in render_in so the cache is fully invalidated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@joelhawksley joelhawksley merged commit 5609f5c into ViewComponent:main Apr 14, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants