You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'll be using Rails along with turbo-rails helpers to describe the problem here but I don't think this is specific to that gem.
Reproduced with:
Rails 7.1.3.2
turbo-rails 2.0.5 (which appears to vendor Turbo 8.0.4)
Description
If a Turbo stream action with action="replace" is received, followed by a refresh action, then the resulting page content after the refresh request can be "out of sync" if there are data-turbo-permanent elements present. "Out of sync" meaning that child elements don't align with their expected parents, causing sometimes subtle, hard-to-identify bugs.
The problem does not appear if there is no replace action and only a refresh is used.
The #el-* elements are out of sync with their corresponding #perma-* elements.
This is quite surprising, and can lead to subtle bugs. For instance, if #perma-N contains a form element referencing record N but is displayed as associated with some other record (#el-X), then a user might submit the form thinking they're updating, in this case, say, the record for #el-3, but in reality they're updating the record for #el-2.
The way the bug manifests appears to depend on HTML structure, and a change in the placement of the "replace" target affects whether the bug appears.
If the replace action is never sent/received, then the page structure is as expected, which maybe indicates there's some kind of conflicting state somewhere.
If #replace-target is moved below.abc, then the desync doesn't happen and the resulting structure is as expected:
In other situations, the structure of .abc appears to affect the resulting desync. In a production app the desync was seen as changing from (el, perma) pairs from:
(1, 1)
(2, 2)
(3, 3)
To:
(2, 2)
(3, 2)
Instead of:
(2, 2)
(3, 3)
Reproduction
Here's a setup script to reproduce it with a fresh Rails app. A file in /tmp is used to control whether #el-1 is included or not, which is a little hacky but avoids needing to edit templates.
I'll be using Rails along with turbo-rails helpers to describe the problem here but I don't think this is specific to that gem.
Reproduced with:
Description
If a Turbo stream action with
action="replace"
is received, followed by a refresh action, then the resulting page content after the refresh request can be "out of sync" if there aredata-turbo-permanent
elements present. "Out of sync" meaning that child elements don't align with their expected parents, causing sometimes subtle, hard-to-identify bugs.The problem does not appear if there is no replace action and only a refresh is used.
For example, consider some HTML (ERB) like this:
The structure here is:
Next, consider these steps in sequence:
"replace"
action targets#replace-target
, replacing its content.#el-1
in responses. (For example, suppose this is a list of incomplete todo items, and the first item was completed.)The page structure I'd expect after the refresh is:
The actual page structure, however, is:
The
#el-*
elements are out of sync with their corresponding#perma-*
elements.This is quite surprising, and can lead to subtle bugs. For instance, if
#perma-N
contains a form element referencing recordN
but is displayed as associated with some other record (#el-X
), then a user might submit the form thinking they're updating, in this case, say, the record for#el-3
, but in reality they're updating the record for#el-2
.The way the bug manifests appears to depend on HTML structure, and a change in the placement of the
"replace"
target affects whether the bug appears.If the replace action is never sent/received, then the page structure is as expected, which maybe indicates there's some kind of conflicting state somewhere.
If
#replace-target
is moved below.abc
, then the desync doesn't happen and the resulting structure is as expected:In other situations, the structure of
.abc
appears to affect the resulting desync. In a production app the desync was seen as changing from (el, perma) pairs from:To:
Instead of:
Reproduction
Here's a setup script to reproduce it with a fresh Rails app. A file in
/tmp
is used to control whether#el-1
is included or not, which is a little hacky but avoids needing to edit templates.Now, create an empty toggle file and start the server:
touch /tmp/waiting-for-refresh bundle exec rails s
In a separate shell/terminal, run
bundle exec rails c
:Now visit http://localhost:3000/foo in the browser. The structure shown will be:
Next, generate the replace action in the Rails console:
Then tell the server to stop including
#el-1
:Check the browser page, without refreshing the tab, to confirm the replace was processed, and that "REPLACED" appears.
Finally, send a Turbo refresh for the same page:
The page structure will then be desync'd:
As mentioned above:
#replace-target
after.abc
, the bug won't appear.broadcast_replace_later_to
is never used, then the bug won't appear.The text was updated successfully, but these errors were encountered: