Module: ViewComponent::ExperimentallyCacheable
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/view_component/experimentally_cacheable.rb
Overview
Experimental caching support for ViewComponents.
This API is experimental. It may change or be removed in a non-major release. Please share feedback in https://github.com/ViewComponent/view_component/issues/234.
Including this module does two things:
- Registers the component with Rails' template digest tree, so a
<% cache %>block wrapping the component in a view is invalidated when the component's template, Ruby class, sidecar files, or child components change. - Enables the
cache_onmacro, which caches the component's own rendered output.
class MessageComponent < ViewComponent::Base
include ViewComponent::ExperimentallyCacheable
cache_on :message
def initialize(message:)
@message =
end
end
Constant Summary collapse
- NIL_CACHE_VALUE =
Stands in for
nilin the cache key. Without it,expand_cache_keyrendersniland""identically, so two components differing only in that respect would share an entry. :__vc_nil
Instance Method Summary collapse
-
#cache_key(view_context = nil) ⇒ String
The cache key for this rendering of the component.
-
#render_in(view_context, &block) ⇒ Object
Renders the component, reading from and writing to the Rails cache when
cache_onhas been declared.
Instance Method Details
#cache_key(view_context = nil) ⇒ String
The cache key for this rendering of the component.
Combines the component's identity, its source digest, the requested
format and variant, the current locale, and the values declared with
cache_on. Override for full control.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/view_component/experimentally_cacheable.rb', line 204 def cache_key(view_context = nil) lookup_context = view_context&.lookup_context format = __vc_cache_format(lookup_context) parts = [ "view_component", self.class.virtual_path, self.class.cache_digest(finder: lookup_context, format: format), # Included in its own right, not just as a digest input: components that # render every format from one template have the same digest for each. format, __vc_cache_variant(lookup_context), I18n.locale, *__vc_cache_on_values ] # Positions are significant, so nils are substituted rather than removed. # Compacting the array would let a nil in one position collapse into a nil # in another. ActiveSupport::Cache.( parts.map { |part| part.nil? ? NIL_CACHE_VALUE : part } ) end |
#render_in(view_context, &block) ⇒ Object
Renders the component, reading from and writing to the Rails cache when
cache_on has been declared.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/view_component/experimentally_cacheable.rb', line 169 def render_in(view_context, **, &block) return super unless self.class.__vc_caches_output? # Content provided by the caller isn't part of the cache key, so caching # it would serve one caller's content to another. Raised whether or not # caching is currently enabled, so the conflict surfaces in development # and test rather than only in production. if block || __vc_content_set_by_with_content_defined? || __vc_slots_set_by_caller? raise ContentPassedToCachedComponentError.new(self.class.name) end return super unless __vc_cache_enabled?(view_context) store = Rails.cache key = cache_key(view_context) if (cached = store.read(key)) # Safe to mark as HTML-safe: the cached string was produced by this same # rendering pipeline, which escapes output before it's written. return cached.html_safe # rubocop:disable Rails/OutputSafety end super.tap do |output| store.write(key, output.to_s) end end |