Rendering partial into component
florentferry opened this issue · comments
Problem
We need the ability to render partial inside a component. If that partial is inside the component, we need a way to prevent to give full path.
Example:
components/
button/
_button.html.slim
_icon.html.slim
/ frontend/components/button/_button.html.slim
= render("components/button/icon")
Solution 1
Add components
folder and all subfolders to lookup. But the drawback is the addition of a lot of directories to lookup.
ActionController::Base.prepend_vew_path Dir["#{app.config.root}/frontend/**/*"]
/ frontend/components/button/_button.html.slim
= render("button/icon")
Solution 2
Add a render_partial
helper to render partial inside component. We inject current component path to lookup in order to render the component, and restore default behavior after rendering.
def render_partial(partial_name, locals = {}, &block)
benchmark("Rendered partial #{partial_name}") do
context = controller.view_context
view_paths = context.lookup_context.view_paths.dup
components_path = Rails.root.join "frontend/components"
capture_block = proc { capture(&block) } if block
current_dir = Pathname.new(@virtual_path).dirname
context.lookup_context.prefixes.prepend current_dir
context.lookup_context.view_paths.unshift components_path
partial_rendered = capture do
context.render partial_name, locals, &capture_block
end
context.lookup_context.prefixes.delete current_dir
context.lookup_context.view_paths = view_paths
partial_rendered
end
end
/ frontend/components/button/_button.html.slim
= render_partial("icon")
Solution 3
Allow to have nested components inside component.
components/
button/
_button
...
title/
_title
...
I like solution 2. It's not something that would happen in all components, so I think this approach is specific enough and does not seem to have impact on the rest of the features / architecture.