Thanks for asking this question, @krzykamil! This is definitely possible.
To answer the question, let’s start by looking at how Hanami views themselves can have their layout specified. This is typically done via config.layout = "standard_layout"
in a view class body, but you can also change it at call time, too: my_view.call(layout: "different_layout")
.
Next, we can look at how views are called from actions. Views are rendered on the action’s response, like so:
response.render(view, **options)
Under the hood, rendering on a response will call
the view object and pass those options (among others) as arguments:
def render(view, **input)
view_input = {
**view_options.call(request, self),
**exposures,
**input
}
self.body = view.call(**view_input).to_str
end
This already gives us one approach for changing the layout when an action is called: update our handle
method to render the view and specify the layout as required:
def handle(request, response)
# `view` is automatically available if we have a matching view class
response.render(view, layout: "different_layout")
end
In the above approach, you can add whatever logic you need to change "different_layout"
to the right value for your circumstances. I presume you want to inspect headers and change the layout if the request is made by HTMX, or similar.
This approach is fine, but it’s probably not the cleanest if you wanted to apply this behaviour to a large number of actions. For this, the code snippet above from hanami-controller points us to another approach, which is its use of the #view_options
action method.
We could overload this method to set our view layout for our needs:
def view_options(request, response)
# Layouts can be `nil` (for no layout) as well as strings
options = {}
options[:layout] = nil if request.headers["HX-Request"] == "true"
{**super, **options}
end
This will automatically set the layout name without requiring you to do so explicitly inside your #handle
methods. If you put this in a base action class, then it will work for all its subclasses!
Hopefully this gets you on the right path. Please give this a try and let me know how you go!