Skip to content

Commit 5609f5c

Browse files
authored
Merge pull request #2603 from armstrjare/fix/stale-content-cache-on-slot-access
Fix stale content cache when slots are accessed before render_in
2 parents 4e38c65 + b43e9b9 commit 5609f5c

File tree

4 files changed

+34
-0
lines changed

4 files changed

+34
-0
lines changed

docs/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ nav_order: 6
1010

1111
## main
1212

13+
* Fix stale content cache when slots are accessed before `render_in`.
14+
15+
*Jared Armstrong*
16+
1317
* Add rubocop-view_component to resources.
1418

1519
*Andy Waite*

lib/view_component/base.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ def render_in(view_context, &block)
131131
end
132132

133133
@__vc_content_evaluated = false
134+
remove_instance_variable(:@__vc_content) if defined?(@__vc_content)
134135
@__vc_render_in_block = block
135136
@view_context.instance_variable_set(:@virtual_path, virtual_path)
136137

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
class SlotWithContentBlockComponent < ViewComponent::Base
4+
renders_one :header
5+
6+
def call
7+
out = +""
8+
out << content_tag(:div, header, class: "header") if header?
9+
out << content_tag(:div, content, class: "body") if content?
10+
out.html_safe
11+
end
12+
end

test/sandbox/test/slotable_test.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,23 @@ def test_slot_name_methods_are_not_shared_accross_components
822822
assert_not_equal SlotsComponent.instance_method(:title).owner, SlotNameOverrideComponent::OtherComponent.instance_method(:title).owner
823823
end
824824

825+
def test_slot_predicate_before_render_does_not_poison_content_cache
826+
component = SlotWithContentBlockComponent.new
827+
component.with_header { "My Header" }
828+
829+
# Accessing a slot predicate before render_in triggers content evaluation
830+
# via __vc_get_slot. Without the fix, this caches a nil @__vc_content that
831+
# persists through render_in, causing the content block to be silently ignored.
832+
assert component.header?
833+
834+
render_inline(component) do
835+
"Body content from block"
836+
end
837+
838+
assert_selector(".header", text: "My Header")
839+
assert_selector(".body", text: "Body content from block")
840+
end
841+
825842
def test_allows_marking_slot_as_last
826843
render_inline(LastItemComponent.new) do |component|
827844
component.with_item("animal")

0 commit comments

Comments
 (0)