Created
January 8, 2024 17:40
-
-
Save willcosgrove/37c00cb84fd7e448f37e47f843d14032 to your computer and use it in GitHub Desktop.
A remix of @bradgessler's Phlexable concern described here: https://fly.io/ruby-dispatch/hacking-rails-implicit-rendering-for-view-components/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This concern will augment the default rendering behavior of a controller. If | |
# no matching view template is found for an action, a Phlex view will be | |
# searched for. First at a constant defined within the controller that matches | |
# the name of the action (`Edit`, `Index`, etc), and then within the views | |
# folder defined under `#{controller_name}::#{action_name}Page` | |
# (e.g. Admin::Bottles::IndexPage) | |
# | |
# If a matching Phlex view is found, it will be initialized with the defined | |
# instance variables that match it's own attributes (defined using the | |
# `attribute` macro). | |
module Phlexable | |
extend ActiveSupport::Concern | |
class_methods do | |
def phlex_action_class(action:) | |
action_class_name = action.to_s.camelcase | |
return const_get(action_class_name) if const_defined?(action_class_name) | |
"#{self.name.delete_suffix("Controller")}::#{action.to_s.camelcase}Page".safe_constantize | |
end | |
end | |
protected | |
# Phlex views define their attributes using the `attribute` method. If the | |
# controller has an instance variable with the same name as the attribute, it | |
# will be passed to the view as an argument. | |
def build_phlex_initializer_arguments(phlex_view) | |
needed_attributes = phlex_view.literal_attributes.keys | |
needed_attributes.filter_map do |attribute| | |
string_attribute = attribute.to_s | |
[attribute, view_assigns[string_attribute]] if view_assigns.key?(string_attribute) | |
end.to_h | |
end | |
# Initializes a Phlex view based on the action name. | |
def phlex_action(action) | |
phlex_class = self.class.phlex_action_class(action: action) | |
return unless phlex_class | |
arguments = build_phlex_initializer_arguments(phlex_class) | |
phlex_class.new(**arguments) | |
end | |
# Phlex action for the current action. | |
def phlex | |
phlex_action(action_name) | |
end | |
# Try rendering with the regular Rails rendering methods; if those don't work | |
# then try finding the Phlex class that corresponds with the action_name. If that's | |
# found then tell Rails to call `default_phlex_render`. | |
def method_for_action(action_name) | |
super || if self.class.phlex_action_class action: action_name | |
"default_render" | |
end | |
end | |
# Renders a Phlex view for the given action, if it's present. | |
def default_render | |
render phlex, layout: false | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment