How to conditionally restore from server?

I have a typical index page with hundreds of items. When user clicks on an item they are sent to a details page. On that details page the user is able to “favorite” the item. By clicking a heart a POST is sent to the server and the icon is updated (page is not refreshed). When the user hits the back button, a restoration visit is invoked and the index page is rendered from cache and no hearts appear. This is expected of course because of the restoration visit.

I can get around this by specifying <meta name="turbo-cache-control" content="no-cache">, but that causes the page to be requested from the server. While it solves my problem, the reality is that for 99% of the time, my users won’t favorite an item so I’d like to be able to restore from the cache.

Is there a good way around this? When clicking the back button, restore from cache but occasionally restore from server?

Thanks!

This is a really common pattern, so I’m surprised there isn’t something already in the library to help handle it. You might want to start by looking at what you could change in the response from the heart-click action that might allow you to modify the history so the back button works correctly. There are a lot of methods in Turbo which can do this sort of low-level history stack modification, it’s just going to be a matter of triggering them.

You mention that the icon is being updated; is that through an Ajax UJS response, or a TurboStream, or some other method? If you can get that response to also trigger a Turbo method in the currently-loaded page that would silently replace the previous history stack entry with a refreshed version of the index page, that would probably do the trick.

Walter

This is a really common pattern, so I’m surprised there isn’t something already in the library to help handle it.

I agree, or perhaps have a part of the documentation around common patterns or how-tos.

You mention that the icon is being updated; is that through an Ajax UJS response, or a TurboStream, or some other method?

I’m using a turbo-frame wrapping a form that contains a single checkbox.

OK, I have it solved for most cases, but I think it could be done better.

I have a partial the renders the favorite when the page is first loaded. I conditionally exclude the clearing of the cache and the effect is that hitting the back button will result in the page being loaded from the cache.

If the user instead clicks the favorite, the request is made to the backend, where the partial is returned, but this time the javascript is included which calls Turbo.cache.clear().

= turbo_frame_tag('favourite-tf') do
  .favourite
    = form_with model: [:favourite, model] do |form|
      - favourited = current_user.favoured?(model)
      = check_box_tag :favourite, true, favourited, {onchange: 'this.form.requestSubmit()', class: 'd-none'}
      = label_tag(:favourite) do
        = favourite_img(favourited)

  - if clear_turbo_cache
    :javascript
      Turbo.cache.clear();

I suppose it might be better if I could clear the cache of just the page that a “back” button click would return to, but this works OK.