You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e86cfda
Browse filesBrowse the repository at this point in the historyBrowse files
Raise when a caller sets a slot on a self-caching component
Slot content set by the caller is no more part of the cache key than a
block is, so it carries the same risk of serving one caller's content to
another.
Checked before rendering via @__vc_set_slots, which callers populate
through `with_*` setters. Slots a component fills in for itself with a
`default_*` method resolve lazily during the render, so they aren't
counted and are cached normally.
Copy file name to clipboardExpand all lines: docs/api.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -467,9 +467,9 @@ Content for slot SLOT_NAME has already been provided.
467
467
468
468
### `ContentPassedToCachedComponentError`
469
469
470
-
Content was passed to COMPONENT, which caches its own output because it declares `cache_on`.
470
+
COMPONENT declares `cache_on`, so it caches its own output, but its caller passed it content.
471
471
472
-
Content provided by the caller isn't part of the cache key, so caching it would risk serving one caller's content to another.
472
+
Content and slots set by the caller aren't part of the cache key, so caching them would risk serving one caller's content to another.
473
473
474
474
To fix this issue, either remove `cache_on` from COMPONENT, or move the content into the component and derive it from the values declared in `cache_on`.
Copy file name to clipboardExpand all lines: docs/guide/caching.md
+22-3Lines changed: 22 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -158,20 +158,39 @@ Declared components must include `ViewComponent::ExperimentallyCacheable` themse
158
158
159
159
## Caveats
160
160
161
-
**Self-caching components can't take content.** Content passed by the caller isn't part of the cache key, so caching it would risk serving one caller's content to another. Passing a block or `with_content` to a component that declares `cache_on` raises:
161
+
**Self-caching components can't take content from their callers.** Content passed by the caller isn't part of the cache key, so caching it would risk serving one caller's content to another. Passing a block, `with_content`, or a slot to a component that declares `cache_on` raises:
162
162
163
163
```erb
164
164
<%# Raises ContentPassedToCachedComponentError %>
165
165
<%= render PostComponent.new(post: @post) do %>
166
166
Hello
167
167
<% end %>
168
+
169
+
<%# Also raises %>
170
+
<%= render PostComponent.new(post: @post) do |component| %>
171
+
<% component.with_header { "Hello" } %>
172
+
<% end %>
168
173
```
169
174
170
175
The error is raised whether or not caching is enabled, so the conflict surfaces in development and test rather than only in production.
171
176
172
-
To cache a component that takes content, move the content into the component and derive it from values declared in `cache_on`. Components that don't declare `cache_on` are unaffected: they still accept content, and a `<% cache %>` block around them still invalidates correctly.
177
+
Slots a component fills in for itself with a `default_*` method are part of its own output, not the caller's, so those are cached normally:
178
+
179
+
```ruby
180
+
classPostComponent < ViewComponent::Base
181
+
includeViewComponent::ExperimentallyCacheable
182
+
183
+
renders_one :header
184
+
185
+
cache_on :post
186
+
187
+
defdefault_header
188
+
post.title # cached, because the component decides it
189
+
end
190
+
end
191
+
```
173
192
174
-
**Slot content set by the caller isn't part of the key either**, and isn't currently detected. Declare the values it depends on in `cache_on`.
193
+
To cache a component that takes content, move the content into the component and derive it from values declared in `cache_on`. Components that don't declare `cache_on` are unaffected: they still accept content and slots, and a `<% cache %>` block around them still invalidates correctly.
175
194
176
195
**`cache_on` methods run before the component renders**, so they can only depend on the component's own state, not on `helpers` or the view context. A cache key that depends on the view context is usually a sign the value should be passed to the component instead.
0 commit comments