diff --git a/app/controllers/frame_requests_controller.rb b/app/controllers/frame_requests_controller.rb
new file mode 100644
index 00000000..f87630d8
--- /dev/null
+++ b/app/controllers/frame_requests_controller.rb
@@ -0,0 +1,2 @@
+class FrameRequestsController < ApplicationController
+end
diff --git a/app/controllers/turbo/frames/frame_request.rb b/app/controllers/turbo/frames/frame_request.rb
index 229c094b..7e28ee53 100644
--- a/app/controllers/turbo/frames/frame_request.rb
+++ b/app/controllers/turbo/frames/frame_request.rb
@@ -2,10 +2,25 @@
# that frame, not the whole page. They are automatically tagged as such by the Turbo Frame JavaScript, which adds a
# Turbo-Frame header to the request.
#
+# When the Turbo-Frame header is present, the request's variant
+# will be marked turbo_frame.
+#
+# As an optimization, applications can declare a layout with the
+# html+turbo_frame.erb extension that renders
+# without the navigation and layout elements:
+#
+# <%= app/views/layouts/application.html+turbo_frame.erb %>
+# <%= yield %>
+#
# This module is automatically included in ActionController::Base.
module Turbo::Frames::FrameRequest
extend ActiveSupport::Concern
+ included do
+ before_action -> { request.variant.push :turbo_frame }, if: :turbo_frame_request?
+ end
+
private
def turbo_frame_request?
request.headers["Turbo-Frame"].present?
diff --git a/test/dummy/app/views/frame_requests/index.html.erb b/test/dummy/app/views/frame_requests/index.html.erb
new file mode 100644
index 00000000..6df570a3
--- /dev/null
+++ b/test/dummy/app/views/frame_requests/index.html.erb
@@ -0,0 +1 @@
+
<%= controller_name %>/<%= action_name %>
diff --git a/test/dummy/app/views/layouts/frame_requests.html+turbo_frame.erb b/test/dummy/app/views/layouts/frame_requests.html+turbo_frame.erb
new file mode 100644
index 00000000..37f0bddb
--- /dev/null
+++ b/test/dummy/app/views/layouts/frame_requests.html+turbo_frame.erb
@@ -0,0 +1 @@
+<%= yield %>
diff --git a/test/dummy/app/views/layouts/frame_requests.html.erb b/test/dummy/app/views/layouts/frame_requests.html.erb
new file mode 100644
index 00000000..c47e8bf7
--- /dev/null
+++ b/test/dummy/app/views/layouts/frame_requests.html.erb
@@ -0,0 +1,8 @@
+
+
+ <%= controller_name %>/<%= action_name %>
+
+
+ <%= yield %>
+
+
diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb
index 17f3af84..02de2efe 100644
--- a/test/dummy/config/routes.rb
+++ b/test/dummy/config/routes.rb
@@ -1,4 +1,5 @@
Rails.application.routes.draw do
+ resources :frame_requests
resources :messages
resources :trays
resources :posts
diff --git a/test/frames/frame_request_controller_test.rb b/test/frames/frame_request_controller_test.rb
index 4999d0e1..3dd13e5b 100644
--- a/test/frames/frame_request_controller_test.rb
+++ b/test/frames/frame_request_controller_test.rb
@@ -1,6 +1,16 @@
require "turbo_test"
class Turbo::FrameRequestControllerTest < ActionDispatch::IntegrationTest
+ test "frame request have turbo_frame variant" do
+ get frame_requests_path
+
+ assert_select "title", count: 1, text: "frame_requests/index"
+
+ get frame_requests_path, headers: { "Turbo-Frame" => "true" }
+
+ assert_select "title", count: 0
+ end
+
test "frame requests are rendered with a layout" do
get tray_path(id: 1)
assert_select "title", count: 1