Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include minimal layout in frame responses #428

Merged
merged 1 commit into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions app/controllers/turbo/frames/frame_request.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
# Turbo frame requests are requests made from within a turbo frame with the intention of replacing the content of just
# that frame, not the whole page. They are automatically tagged as such by the Turbo Frame JavaScript, which adds a
# <tt>Turbo-Frame</tt> header to the request. When that header is detected by the controller, we ensure that any
# template layout is skipped (since we're only working on an in-page frame, thus can skip the weight of the layout), and
# that the etag for the page is changed (such that a cache for a layout-less request isn't served on a normal request
# and vice versa).
# <tt>Turbo-Frame</tt> header to the request.
#
# This is merely a rendering optimization. Everything would still work just fine if we rendered everything including the layout.
# Turbo Frames knows how to fish out the relevant frame regardless.
# When that header is detected by the controller, we substitute our own minimal layout in place of the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about mentioning the minimal layout is turbo_rails/frame.html.erb? People can still override the default if the want creating their own app/views/layouts/turbo_rails/frame.html.erb file. Probably not a very common case, but still doable if someone wants to do it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about mentioning the minimal layout is turbo_rails/frame.html.erb? People can still override the default if the want creating their own app/views/layouts/turbo_rails/frame.html.erb file.

I like that idea. Action Text's documentation makes a similar suggestion for folks needing to customize the default layout in https://guides.rubyonrails.org/action_text_overview.html#rendering-rich-text-content

# application-supplied layout (since we're only working on an in-page frame, thus can skip the weight of the layout). We
# use a minimal layout, rather than avoid the layout entirely, so that it's still possible to render content into the
# <tt>head<tt>.
#
# Accordingly, we ensure that the etag for the page is changed, such that a cache for a minimal-layout request isn't
# served on a normal request and vice versa.
#
# This is merely a rendering optimization. Everything would still work just fine if we rendered everything including the
# full layout. Turbo Frames knows how to fish out the relevant frame regardless.
#
# The layout used is <tt>turbo_rails/frame.html.erb</tt>. If there's a need to customize this layout, an application can
# supply its own (such as <tt>app/views/layouts/turbo_rails/frame.html.erb</tt>) which will be used instead.
#
# This module is automatically included in <tt>ActionController::Base</tt>.
module Turbo::Frames::FrameRequest
extend ActiveSupport::Concern

included do
layout -> { false if turbo_frame_request? }
layout -> { "turbo_rails/frame" if turbo_frame_request? }
etag { :frame if turbo_frame_request? }
end

Expand Down
8 changes: 8 additions & 0 deletions app/views/layouts/turbo_rails/frame.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<%= yield :head %>
</head>
<body>
<%= yield %>
</body>
</html>
4 changes: 4 additions & 0 deletions test/dummy/app/views/trays/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<% content_for :head do %>
<meta name="test" content="present" />
<% end %>

<turbo-frame id="tray">
<div>This is a tray!</div>
<div><%= @frame_id %></div>
Expand Down
27 changes: 26 additions & 1 deletion test/frames/frame_request_controller_test.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
require "test_helper"

class Turbo::FrameRequestControllerTest < ActionDispatch::IntegrationTest
test "frame requests are rendered without a layout" do
test "frame requests are rendered with a minimal layout" do
get tray_path(id: 1)
assert_select "title", count: 1

get tray_path(id: 1), headers: { "Turbo-Frame" => "true" }
assert_select "title", count: 0
end

test "frame request layout includes `head` content" do
get tray_path(id: 1), headers: { "Turbo-Frame" => "true" }

assert_select "head", count: 1
assert_select "meta[name=test][content=present]"
end

test "frame request layout can be overridden" do
with_prepended_view_path "test/frames/views" do
get tray_path(id: 1), headers: { "Turbo-Frame" => "true" }
end

assert_select "meta[name=test][content=present]"
assert_select "meta[name=alternative][content=present]"
end

test "frame requests get a unique etag" do
get tray_path(id: 1)
etag_without_frame = @response.headers["ETag"]
Expand All @@ -28,4 +44,13 @@ class Turbo::FrameRequestControllerTest < ActionDispatch::IntegrationTest
get tray_path(id: 1), headers: { "Turbo-Frame" => turbo_frame_request_id }
assert_match /#{turbo_frame_request_id}/, @response.body
end

private
def with_prepended_view_path(path, &block)
previous_view_paths = ApplicationController.view_paths
ApplicationController.prepend_view_path path
yield
ensure
ApplicationController.view_paths = previous_view_paths
end
end
9 changes: 9 additions & 0 deletions test/frames/views/layouts/turbo_rails/frame.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html>
<head>
<meta name="alternative" content="present" />
<%= yield :head %>
</head>
<body>
<%= yield %>
</body>
</html>