-
Notifications
You must be signed in to change notification settings - Fork 430
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
Back button is not working for turbo advance targeting a frame when rendered inside rails #1300
Comments
When you render through a rails controller, turbo frame requests are rendered within a "turbo_rails/frame" layout. The problem is that this layout has an empty head tag which creates an incorrect snapshot. I've noticed turbo/src/core/drive/page_renderer.js Lines 92 to 94 in f88bfe4
This also seems to only happen on initial page load, if you navigate to the test page with turbo first and then click the link everything works fine. If this is something you need to fix now, you could force to always render layout |
I've made a rails test script. I've also noticed that if you remove require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
gem "rails"
gem "propshaft"
gem "puma"
gem "sqlite3", "~> 1.4"
gem "turbo-rails"
gem "capybara"
gem "cuprite", require: "capybara/cuprite"
end
ENV["DATABASE_URL"] = "sqlite3::memory:"
ENV["RAILS_ENV"] = "test"
require "active_record/railtie"
# require "active_storage/engine"
require "action_controller/railtie"
require "action_view/railtie"
# require "action_mailer/railtie"
# require "active_job/railtie"
require "action_cable/engine"
# require "action_mailbox/engine"
# require "action_text/engine"
require "rails/test_unit/railtie"
class App < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f
config.root = __dir__
config.hosts << "example.org"
config.eager_load = false
config.session_store :cookie_store, key: "cookie_store_key"
config.secret_key_base = "secret_key_base"
config.consider_all_requests_local = true
config.action_cable.cable = {"adapter" => "async"}
config.turbo.draw_routes = false
Rails.logger = config.logger = Logger.new($stdout)
routes.append do
root to: "application#index"
get "frame", to: "application#frame"
end
end
Rails.application.initialize!
class ApplicationController < ActionController::Base
include Rails.application.routes.url_helpers
def index
render inline: <<~TEMPLATE, formats: :html
<html>
<head>
<%= csrf_meta_tags %>
<script type="importmap" data-turbo-track="reload">
{ "imports": { "@hotwired/turbo-rails": "<%= asset_path("turbo.js") %>" } }
</script>
<script type="module">
import "@hotwired/turbo-rails"
</script>
</head>
<body>
<turbo-frame id="my-frame"><div>initial frame</div></turbo-frame>
<a id="frame-link" href="/frame" data-turbo-frame="my-frame" data-turbo-action="advance">click</a>
</body>
</html>
TEMPLATE
end
def frame
# not sure how to stuff layouts into this bug template
# simulate how a turbo_rails/frame layout is rendered on a turbo frame request
if turbo_frame_request?
render inline: <<~TEMPLATE, formats: :html
<html>
<head></head>
<body>
<turbo-frame id="my-frame"><div>frame loaded</div></turbo-frame>
<a id="home-link" href="/">home</a>
</body>
</html>
TEMPLATE
else
render inline: <<~TEMPLATE, formats: :html
<html>
<head>
<%= csrf_meta_tags %>
<script type="importmap" data-turbo-track="reload">
{ "imports": { "@hotwired/turbo-rails": "<%= asset_path("turbo.js") %>" } }
</script>
<script type="module">
import "@hotwired/turbo-rails"
</script>
</head>
<body>
<turbo-frame id="my-frame"><div>frame loaded</div></turbo-frame>
<a id="home-link" href="/">home</a>
</body>
</html>
TEMPLATE
end
end
end
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :cuprite,
using: :chrome,
screen_size: [1400, 1400],
options: {
js_errors: true,
headless: true
}
end
Capybara.configure do |config|
config.server = :puma, {Silent: true}
config.default_normalize_ws = true
end
require "rails/test_help"
class TurboSystemTest < ApplicationSystemTestCase
test "not a bug" do
visit "/frame"
click_link "home-link"
assert_text "initial frame"
click_link "frame-link"
sleep 1
assert_text "frame loaded"
go_back
sleep 1
assert_text "initial frame"
end
test "a bug" do
visit "/"
click_link "frame-link"
sleep 1
assert_text "frame loaded"
go_back
sleep 1
assert_text "initial frame" # bug
end
end |
@4lllex That's great that you have a repro and even a hunch about the core comparison that is failing. How hard do you think it would be to tee up a PR for this one? It'd be nice to get it in for Rails 8 |
#1241 looks like the same issue, they have a PR attached but I'm not sure how close it is to an accepted solution. |
The fix seems to be known and it is to revert this line: turbo/src/core/frames/frame_controller.js Line 352 in 7ae9546
Here is a patch in the meantime: Turbo.FrameElement.delegateConstructor.prototype.proposeVisitIfNavigatedWithAction = function(frame, action = null) {
this.action = action
if (this.action) {
// const pageSnapshot = PageSnapshot.fromElement(frame).clone()
const pageSnapshot = Turbo.PageSnapshot.fromElement(frame).clone()
const { visitCachedSnapshot } = frame.delegate
// frame.delegate.fetchResponseLoaded = async (fetchResponse) => {
frame.delegate.fetchResponseLoaded = (fetchResponse) => {
if (frame.src) {
const { statusCode, redirected } = fetchResponse
// const responseHTML = await fetchResponse.responseHTML
const responseHTML = frame.ownerDocument.documentElement.outerHTML
const response = { statusCode, redirected, responseHTML }
const options = {
response,
visitCachedSnapshot,
willRender: false,
updateHistory: false,
restorationIdentifier: this.restorationIdentifier,
snapshot: pageSnapshot
}
if (this.action) options.action = this.action
// session.visit(frame.src, options)
Turbo.session.visit(frame.src, options)
}
}
}
} |
Also confirming, that adding layout, as recommended here, helped. #1300 (comment) |
Confirmed too, but adding a layout didn't solve the problem 😢 File added as `app/views/layouts/turbo_rails/frame.html.haml`!!!
%html{ lang: 'fr-FR' }
%head
%meta{ charset: 'UTF-8' }
= csrf_meta_tags
= yield :head
%body
= yield EDIT: |
I have a really hard bug that I've finally stripped down to an essential repro of it. I can't figure out what's going on.
What the user experiences on my app is:
action="advance"
It's a bad bug because it feels like the back button is broken, which, of course, we want turbo to respect back behavior.
In order to file a bug report, I tried to create a failing test case within this hotwired/turbo.js project. I opened
src/tests/fixtures/frames.html
and set up the test situation did the usualyarn build; yarn start
. Oddly, the back button worked properly. I could not initially repro it.Puzzled, I copied the exact same contents of frames.html over to my rails project and the bug appears! I could not figure out what the difference is since I stripped everything down. The only difference is that one is being served by yarn server and one is being served by rails server and rendering view templates. Then I copied these same files into the rails public/ directory and the bug goes away! For some reason this bug is only present when html & javascript code is served up through rails views. I'm baffled.
I know this is confusing so try watching this video where I show it very simply:
https://share.zight.com/o0uAplQJ
And here is a repository with of a fresh rails app with just the 4 files needed to reproduce it, everything else has been stripped out. Pull this repo and you can try for yourself what I just demonstrated in the video:
https://github.com/krschacht/hotwire-demo
The text was updated successfully, but these errors were encountered: