Visitar URL original
view_component/docs/guide/caching.md at main · ViewComponent/view_component · GitHub
Skip to content

Latest commit

 

History

History
82 lines (56 loc) · 3.18 KB

caching.md

File metadata and controls

82 lines (56 loc) · 3.18 KB
layout default
title Caching
parent How-to guide

Caching

Since 4.14.0 {: .label }

Components work with Rails fragment caching. Editing a component's template, Ruby class, sidecar files, superclasses, included modules, or anything it renders invalidates every cache block that contains it, whether that block is in a view or inside a component's own template:

<% cache @post do %>
  <%= render PostComponent.new(post: @post) %>
<% end %>

Self-caching

Use cache_on to have a component cache its own output, keyed by the values of the named methods:

class PostComponent < ViewComponent::Base
  cache_on :post

  def initialize(post:)
    @post = post
  end

  private

  attr_reader :post
end

The cache key also includes the component's digest, ordered format and variant fallbacks, partial lookup prefixes, and locale. As with Rails' cache helper, caching only happens when perform_caching is enabled.

To cache only some renders, pass if: or unless: with a method name or a proc:

cache_on :post, unless: -> { post.draft? }

A component that declares cache_on can't take content from its callers, since that content isn't part of the cache key. Passing a block, with_content, or a slot raises ContentPassedToCachedComponentError, even when caching is disabled. Slots filled by the component's own default_* methods are fine.

cache_on methods run before the component renders, so they can't use helpers or the view context.

Reading a component's digest

.cache_digest returns the digest of everything a component renders from, for tying a cache to a component outside a render:

Rails.cache.fetch(["post-summary", post, PostComponent.cache_digest]) do
  expensive_summary_for(post)
end

Declaring dependencies

Dependencies are found by scanning the component's templates, its Ruby class, and the modules it includes. Every component class named there counts, whether it's passed to render or a helper, built by a method, or assigned to a variable, and so does every partial rendered by its path. Slots count the class they're declared with, including one named by a string.

Component classes assigned to variables in Rails view templates are tracked too.

Relative partial names, such as render "heading", track matching partials in every directory of the view paths, since the calling controller determines which one renders. Use a full path to limit invalidation to one partial.

A class or partial name built at runtime can't be found that way. Declare it with Rails' # Template Dependency: comment in the Ruby file or template, naming partials by path and components by class:

class PostComponent < ViewComponent::Base
  # Template Dependency: posts/byline
  # Template Dependency: PostSummaryComponent
  # Template Dependency: PostDetailComponent

  def call
    render "Post#{@style.to_s.camelize}Component".constantize.new(post: @post)
  end
end

For facades such as render UI.button, declare the returned component with a Template Dependency comment in the calling template. Dependency discovery doesn't execute facade methods. It ignores unresolved partial guesses but checks literal paths and explicit dependencies.