From 8df0914ce0e032a19966ae6d08d7e22ffdaf1f41 Mon Sep 17 00:00:00 2001 From: Javi R <4920956+rameerez@users.noreply.github.com> Date: Thu, 9 Jul 2026 06:09:46 +0100 Subject: [PATCH] Also keep the inbox fresh on back-navigation (turbo-cache-control) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion to chats--refresh-inbox. That controller heals a MISSED live broadcast on a page that stays OPEN; it does nothing for the other inbox-staleness case: a Turbo RESTORATION visit (browser back / Hotwire Native stack pop) serves the inbox's cached snapshot with no GET. Open a chat from a profile, send a message, tap back — the snapshot cached before the chat existed returns and the new conversation is missing until you navigate away and return (pull-to-refresh is commonly disabled on the native inbox tab). `turbo-cache-control: no-cache` makes the inbox uncacheable, so a restore visit re-fetches from the network — fresh on web AND in Hotwire Native (back-pop issues a Turbo `.restore` visit that honors it; bundled turbo.js marks a no-cache page isCacheable=false, so restore falls through to a network fetch). Requires the host layout to `yield :head`; harmless no-op otherwise. The dummy layout now yields :head so the suite can assert it. --- app/views/chats/conversations/index.html.erb | 16 ++++++++++++++++ .../dummy/app/views/layouts/application.html.erb | 1 + test/integration/conversations_flow_test.rb | 12 ++++++++++++ 3 files changed, 29 insertions(+) diff --git a/app/views/chats/conversations/index.html.erb b/app/views/chats/conversations/index.html.erb index 855d4c4..e97dba7 100644 --- a/app/views/chats/conversations/index.html.erb +++ b/app/views/chats/conversations/index.html.erb @@ -10,6 +10,22 @@ and on return-to-visible. It needs to wrap the that `turbo_stream_from` renders so it can observe its `connected` attribute as the heartbeat. %> + +<%# The OTHER inbox-staleness case, distinct from a missed broadcast: a Turbo + RESTORATION visit (browser back / Hotwire Native stack pop) serves the + inbox's cached snapshot with no GET. Open a chat from a profile, send a + message, tap back — the snapshot cached before the chat existed comes back + and the new conversation is missing until you navigate away and return. + The reconciler above can't help (it only fires on reconnect / visibility, + not on a restore visit). `turbo-cache-control: no-cache` makes the inbox + uncacheable, so a restore visit re-fetches from the network and is always + fresh — on the web AND in Hotwire Native, whose back-pop issues a Turbo + `.restore` visit that honors this. Requires the host layout to + `yield :head` (the Rails convention); harmless no-op otherwise. + https://turbo.hotwired.dev/handbook/building#opting-out-of-caching %> +<% content_for :head do %> + +<% end %> <%= chats_styles %>
<%= turbo_stream_from chats_current_messager, :chats_inbox %> diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb index c869f4a..abcd697 100644 --- a/test/dummy/app/views/layouts/application.html.erb +++ b/test/dummy/app/views/layouts/application.html.erb @@ -6,6 +6,7 @@ <%# No javascript_importmap_tags: the suite asserts engine pins via Rails.application.importmap directly; rendering the tags would need propshaft digests for every pinned file in the dummy. %> + <%= yield :head %> <%= yield %> diff --git a/test/integration/conversations_flow_test.rb b/test/integration/conversations_flow_test.rb index a8d43e8..b587297 100644 --- a/test/integration/conversations_flow_test.rb +++ b/test/integration/conversations_flow_test.rb @@ -82,6 +82,18 @@ class ConversationsFlowTest < ActionDispatch::IntegrationTest assert_select "[data-controller='chats--refresh-inbox'] turbo-cable-stream-source" end + test "the inbox opts out of Turbo caching so back-navigation re-fetches it fresh" do + login_as @alice + get "/messages" + + # The reconciler heals a MISSED live broadcast on an open page; it does NOT + # heal a STALE RESTORED snapshot. A Turbo restoration visit (browser back / + # Hotwire Native stack pop) serves the inbox snapshot cached before the + # latest activity, with no GET. no-cache makes the inbox uncacheable, so a + # restore visit re-fetches from the network and is always fresh. + assert_select "head meta[name='turbo-cache-control'][content='no-cache']", count: 1 + end + test "the inbox hides blocked direct threads" do block_pair!(@alice, @bob) login_as @alice