Adding Parameterized Layouts to phlex-rails
Out of the box, phlex-rails currently doesn't support parameterized layouts. I found a quick way to hack support in.
published April 16, 2023
As of publishing, phlex-rails doesn't allow you to parameterize your layout components. There's a reason for it concerning how Rails handles rendering layouts. Instead, they recommend using content_for
and yield
. This works fine for some use cases, but it doesn't work great when you're converting a layout that uses instance variables to control aspects of the layout.
You can bring your own parameterized layouts by adding the following code to your ApplicationLayout
class:
class Wrapper
def initialize(klass:, args:, kwargs:)
@klass = klass
@instance = klass.new(*args, **kwargs)
end
def render(view, _locals, &block)
@instance.call(view_context: view) do |yielded|
case yielded
when Symbol
output = view.view_flow.get(yielded)
else
output = yield
end
case output
when ActiveSupport::SafeBuffer
@instance.unsafe_raw output
end
nil
end
end
def identifier
@klass.identifier
end
def virtual_path
@klass.virtual_path
end
end
def self.with(*args, **kwargs)
Wrapper.new(klass: self, args: args, kwargs: kwargs)
end
With this, the standard approach to selecting your layout will still work.
layout -> { ApplicationLayout }
When you need to parameterize your layout, use the with
method instead.
layout -> { ApplicationLayout.with(theme: :blue, show_header: false) }
I hope phlex-rails will eventually support this use case, but this snippet solves the problem for now.