Scenario: I have a component of my page that I know to be slow to build. I want to cache it. I want it to load asynchronously on the page whenever it’s built.
It seems that we could combine Turbo/ActiveJob/SomeCache in order to achieve this in a more optimized manner than a javascript poller, a custom API and custom cache.
I continually have been reach for turbo streams in order to solve this problem, but I’ve found the process of stitching all the things together to be a bit cumbersome.
I guess the point of this post is to ask if there is development happening in this area? Either in Rails Core or is anyone familiar with a gem somewhere that might address this?
That said, I’ve built some half-baked solutions which combine the three things. The following is a bit half-baked, but hopefully you get the idea:
helper.rb
def cached_turbo_stream(identifier)
if value = Rails.cache.read(key)
value
else
turbo_stream_from identifier,
channel: "CachedTurboStreamChannel",
id: "cached_turbo_stream_#{identifier}"
end
end
cached_turbo_stream_channel.rb
class CachedTurboStreamChannel < Turbo::StreamsChannel
def subscribed
super
stream_name = verified_stream_name_from_params
CachedTurboStreamJob.perform_later(stream_name)
end
end
cached_turbo_stream_job.rb
class CachedTurboStreamJob < ApplicationJob
def perform(stream_name)
cached_tag =
Rails.cache.fetch(some_cache_key) do
content =
ApplicationController.render(
formats: [:html],
partial: stream_name
)
CachedTurboStreamChannel.turbo_stream_action_tag(
:replace,
target: "cached_turbo_stream_#{stream_name}",
template: content
)
end
CachedTurboStreamChannel.broadcast_stream_to(
stream_name,
content: cached_tag
)
end
end
This thing renders the partial if it’s cached, and if it’s not, set’s up a turbo_stream_for
which, of course, connects to Turbo::StreamsChannel
, drops a job, and that job broadcasts the rendered partial back to the stream which injects it into the dom.
This allows the main page to load quickly, and defers the work of caching this component to ActiveJob. It is then loaded asynchronously when it is ready.