Skip to content

Instantly share code, notes, and snippets.

@willcosgrove
Created January 8, 2024 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save willcosgrove/37c00cb84fd7e448f37e47f843d14032 to your computer and use it in GitHub Desktop.
Save willcosgrove/37c00cb84fd7e448f37e47f843d14032 to your computer and use it in GitHub Desktop.
# 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