Description
Feature request
Components should provide a digest to Rails views, or be able to use Rails explicit caching directive comments or be able to provide a cache_key.
Essentially we should be able to invalidate a cache based on whether the Component class or template has changed.
Motivation
I'm just building on some previous reports primarily around where templates live and the filenames of the template/s. My concerns come down to integrating with Rails caching basics.
The issue that we run into is basically summed up by
## In any view/partial
cache[object, another_object] do
render(MyComponent.new(attribute: value))
end
In this case if the template for MyComponent
is changed the cache will not be invalidated. I tried to add MyComponent
to the array used by cache
and provide a self.cache_key
method that used ActionView::Digestor
but without having some further mechanism to invalidate the digestor's cache for the template/s when the template changes this didn't work.
Rails allows for explicit directives to be used (https://guides.rubyonrails.org/caching_with_rails.html#explicit-dependencies) but by default this will only look inside app/views
. You can add a view path append_view_path("app/components")
but the digestor is expecting a partial and so a template filename would have to be prefixed with underscore.
The way we are currently working around this is to have an ApplicationComponent
that our components inherit from and where we override ActionView::Component::Base.matching_views_in_source_location
so that templates are now found in app/views/component_templates
and where the files are prefixed with underscore.
def self.matching_views_in_source_location
return [] unless source_location
*path, file_name = source_location.chomp(File.extname(source_location)).split("/")
path.pop # remove components
path.concat(["views", "component_templates"])
path_to_template = path.push("_#{ file_name }").join("/")
Dir["#{ path_to_template }.*{#{ActionView::Template.template_handler_extensions.join(',')}}"]
end
Then in the above example where cache invalidation does not work via template digest changes we can do
## In any view/partial
# Template Dependency: component_templates/my_component %>
cache[object, another_object] do
render(MyComponent, attribute: value)
end
I think if AV::C is going to be core or integrate with Rails it would need a way to expose template digests nicely, or provide cache_key
probably at the class level. If not then as a last resort we would need a way to use explicit directives in templates that use ActionView::Components internally.
I'd also be all 👂 to people who have solved this already or if I've missed something about the features ActionView::Component
provides!