Caching experimental
Phlex uses an in-memory FIFO store to cache sets of HTML attributes to improve performance. This cache is limited to the bytesize of the Ruby files that define each of your Phlex components.
Basing the cache constraint on this means it grows and shrinks with your app, while always being constrained to a reasonable size. There is currently no way to configure this cache. It’s on by default and defaults to a reasonable size.
Fragment caching
You can cache fragments of your component templates using the cache
method. This method takes a set of cache keys and a block.
def view_template
cache(@user, @article) do
h1 { @article.title }
end
end
The block will be yielded only when there is a cache miss. Otherwise, it will render the cached fragment from last time. All positional arguments will be treated as cache keys.
You can also pass keyword arguments, which will be delegated to the fetch
method on the configured cache store. It’s up to the cache store which options it supports.
cache(@article, expires_in: 12.hours) do
h1 { @article.title }
end
Phlex will supplement your cache keys with a few of its own:
- The time in milliseconds that the app was booted and Phlex was loaded. This invalidates the cache on each deploy in case a template has changed.
- The name of the current class. This prevents collisions between classes.
- The name of the current method. This prevents collisions between different methods in the same component class.
- The line number where the cache method is called. This prevents collisions between different lines, especially when no custom cache keys are provided.
Low-level fragment caching
low_level_cache
is the same as cache
except you control the entire cache key. Phlex will not supplement its own keys so it’s up to you to make sure your cache will be invalidated correctly. This method takes only one cache key, but you can pass an Array. This allows you maximum control.
low_level_cache([@article], expires_in: 12.hours) do
h1 { @article.title }
end
The cache store interface
Cache stores must respond to fetch(key, &block)
and must return either the result of yielding the block or a previously stored result of yielding the block.
They may also take options as keyword arguments to fetch
. Keyword arguments passed to cache
or low_level_cache
will be delegated to the fetch
call.
Configuring a cache store
To configure a cache store, you just need to define the cache_store
method to return an object implementing the cache store interface. Phlex provides a cache store called Phlex::FIFOCacheStore
. You can use it like this:
class Components::Base
CACHE = Phlex::FIFOCacheStore.new(
max_bytesize: 20_000_000 # 20MB
)
def cache_store
CACHE
end
end
It’s important to store the FIFOCacheStore in a constant. If we had initialized it from inside the cache_store
method, we would get a new store each time that method is called and we’d never cache anything.
Using the Rails cache Rails
Since Phlex’ cache store interface is a subset of Rails’ cache store interface, any Rails cache store should be a valid Phlex cache store.
class Components::Base
def cache_store
Rails.cache
end
end
Supported keys
It’s up to the cache store which keys they support. The Phlex::FIFOCacheStore
supports the following:
String
,Symbol
,Integer
,Float
,Time
,true
,false
,nil
- Objects that respond to
cache_key_with_version
orcache_key
Array
andHash
collections of the above
Since Rails also uses the cache_key_with_version
/cache_key
interface, it should be possible to cache things like ActiveRecord models using the Phlex::FIFOCacheStore
. However, if you’re using Rails, you should probably just configure your Rails cache store.
Reloading the cache during development
Phlex has an enable_cache_reloading?
method that defaults to returning false
. When this returns true
, the cache method will include the class’ object_id
as one of its keys. When Zeitwerk reloads your application, each autoloaded Ruby class is redefined and gets a new object_id
.
phlex-rails
overrides enable_cache_reloading?
to return true
if your Rails application environment is development
.