One thing I really like about Phlex is how easy it is to group concerns into one place. Consider this Turbo Pagemorphs example. The view has a section in it with a bunch of turbo_
methods.
class View::Post < View::Base
# Includes the turbo_stream_from method
include Phlex::Rails::Helpers::TurboStreamFrom
def initialize(post:)
@post = post
end
# All of our Turbo Stream behavior is configured from one place.
def turbo_refresh_method = "replace"
def turbo_refresh_scroll = "preserve"
def turbo_streams
turbo_stream_from @post.comments
end
def view_template
h1 { @post.title }
main(class: "prose"){
safe render @post.body, type: :md
}
div(id: "comments") do
comments.each do |comment|
div(class: "comment") do
p { comment.body }
end
end
end
end
end
The base layout then implements those methods in the head
and body
tags.
class View::Base < View::Component
# Default to `nil` so we're not morphing all pages
def turbo_refresh_method = nil
# Default to `nil` so we're not scrolling to the top of the page
def turbo_refresh_scroll = nil
# Put all subscriptions here in the subclass.
def turbo_streams = nil
def around_template
head do
# Other meta tags
meta(name: "turbo-pageload", content: turbo_refresh_method)
meta(name: "turbo-refresh-scroll", content: turbo_refresh_scroll)
# More meta tags...
end
# Renders the body ...
body do
yield
turbo_streams
end
# Whatever else ...
end
end
When the layout renders, it uses the methods from the subclass to set the values. If none are set, it defaults to the nil values set in the layout class.
I cover this in the Phlex on Rails course, and even more advanced techniques for organizing view concerns like Turbo, OpenGraph, and more by class composition.