davideisinger.com

My personal website
Log | Files | Refs | README

index.md (4723B)


      1 ---
      2 title: "Five Turbo Lessons I Learned the Hard Way"
      3 date: 2021-08-02T00:00:00+00:00
      4 draft: false
      5 canonical_url: https://www.viget.com/articles/five-turbo-lessons-i-learned-the-hard-way/
      6 ---
      7 
      8 We've been using [Turbo](https://turbo.hotwired.dev/) on our latest
      9 client project (a Ruby on Rails web application), and after a slight
     10 learning curve, we've been super impressed by how much dynamic behavior
     11 it's allowed us to add while writing very little code. We have hit some
     12 gotchas (or at least some undocumented behavior), often with solutions
     13 that lie deep in GitHub issue threads. Here are a few of the things
     14 we've discovered along our Turbo journey.
     15 
     16 ### Turbo Stream fragments are server responses (and you don't have to write them by hand)
     17 
     18 [The docs on Turbo Streams](https://turbo.hotwired.dev/handbook/streams)
     19 kind of bury the lede. They start out with the markup to update the
     20 client, and only [further
     21 down](https://turbo.hotwired.dev/handbook/streams#streaming-from-http-responses)
     22 illustrate how to use them in a Rails app. Here's the thing: you don't
     23 really need to write any stream markup at all. It's (IMHO) cleaner to
     24 just use the built-in Rails methods, i.e.
     25 
     26 ```ruby
     27 render turbo_stream: turbo_stream.update("flash", partial: "shared/flash")
     28 ```
     29 
     30 And though [DHH would
     31 disagree](https://github.com/hotwired/turbo-rails/issues/77#issuecomment-757349251),
     32 you can use an array to make multiple updates to the page.
     33 
     34 ### Send `:unprocessable_entity` to re-render a form with errors
     35 
     36 For create/update actions, we follow the usual pattern of redirect on
     37 success, re-render the form on error. Once you enable Turbo, however,
     38 that direct rendering stops working. The solution is to [return a 422
     39 status](https://github.com/hotwired/turbo-rails/issues/12), though we
     40 prefer the `:unprocessable_entity` alias (so like
     41 `render :new, status: :unprocessable_entity`). This seems to work well
     42 with and without JavaScript and inside or outside of a Turbo frame.
     43 
     44 ### Use `data-turbo="false"` to break out of a frame
     45 
     46 If you have a link inside of a frame that you want to bypass the default
     47 Turbo behavior and trigger a full page reload, [include the
     48 `data-turbo="false"`
     49 attribute](https://github.com/hotwired/turbo/issues/45#issuecomment-753444256)
     50 (or use `data: { turbo: false }` in your helper).
     51 
     52 *Update from good guy [Leo](https://www.viget.com/about/team/lbauza/):
     53 you can also use
     54 [`target="_top"`](https://turbo.hotwired.dev/handbook/frames#targeting-navigation-into-or-out-of-a-frame)
     55 to load all the content from the response without doing a full page
     56 reload, which seems (to me, David) what you typically want except under
     57 specific circumstances.*
     58 
     59 ### Use `requestSubmit()` to trigger a Turbo form submission via JavaScript
     60 
     61 If you have some JavaScript (say in a Stimulus controller) that you want
     62 to trigger a form submission with a Turbo response, you can't use the
     63 usual `submit()` method. [This discussion
     64 thread](https://discuss.hotwired.dev/t/triggering-turbo-frame-with-js/1622/15)
     65 sums it up well:
     66 
     67 > It turns out that the turbo-stream mechanism listens for form
     68 > submission events, and for some reason the submit() function does not
     69 > emit a form submission event. That means that it'll bring back a
     70 > normal HTML response. That said, it looks like there's another method,
     71 > requestSubmit() which does issue a submit event. Weird stuff from
     72 > JavaScript land.
     73 
     74 So, yeah, use `requestSubmit()` (i.e. `this.formTarget.requestSubmit()`)
     75 and you're golden (except in Safari, where you might need [this
     76 polyfill](https://github.com/javan/form-request-submit-polyfill)).
     77 
     78 ### Loading the same URL multiple times in a Turbo Frame
     79 
     80 I hit an interesting issue with a form inside a frame: in a listing of
     81 comments, I set it up where you could click an edit link, and the
     82 content would be swapped out for an edit form using a Turbo Frame.
     83 Update and save your comment, and the new content would render. Issue
     84 was, if you hit the edit link *again*, nothing would happen. Turns out,
     85 a Turbo frame won't reload a URL if it thinks it already has the
     86 contents of that URL (which it tracks in a `src` attribute).
     87 
     88 The [solution I
     89 found](https://github.com/hotwired/turbo/issues/245#issuecomment-847711320)
     90 was to append a timestamp to the URL to ensure it's always unique.
     91 Works like a charm.
     92 
     93 *Update from good guy
     94 [Joshua](https://www.viget.com/about/team/jpease/): this has been fixed
     95 an a [recent
     96 update](https://github.com/hotwired/turbo/releases/tag/v7.0.0-beta.7).*
     97 
     98 ---
     99 
    100 These small issues aside, Turbo has been a BLAST to work with and has
    101 allowed us to easily build a highly dynamic app that works surprisingly
    102 well even with JavaScript disabled. We're excited to see how this
    103 technology develops.