Files
davideisinger.com/content/elsewhere/five-turbo-lessons-i-learned-the-hard-way/index.md
2023-10-22 23:52:56 -04:00

7.8 KiB

title, date, draft, needs_review, canonical_url
title date draft needs_review canonical_url
Five Turbo Lessons I Learned the Hard Way 2021-08-02T00:00:00+00:00 false true https://www.viget.com/articles/five-turbo-lessons-i-learned-the-hard-way/

We've been using Turbo on our latest client project (a Ruby on Rails web application), and after a slight learning curve, we've been super impressed by how much dynamic behavior it's allowed us to add while writing very little code. We have hit some gotchas (or at least some undocumented behavior), often with solutions that lie deep in GitHub issue threads. Here are a few of the things we've discovered along our Turbo journey.

[]{#turbo-stream-fragments-are-server-responses}

The docs on Turbo Streams kind of bury the lede. They start out with the markup to update the client, and only further down illustrate how to use them in a Rails app. Here's the thing: you don't really need to write any stream markup at all. It's (IMHO) cleaner to just use the built-in Rails methods, i.e.

render turbo_stream: turbo_stream.update("flash", partial: "shared/flash")

And though DHH would disagree, you can use an array to make multiple updates to the page.

[]{#send-unprocessable-entity-to-re-render-a-form-with-errors}

For create/update actions, we follow the usual pattern of redirect on success, re-render the form on error. Once you enable Turbo, however, that direct rendering stops working. The solution is to return a 422 status, though we prefer the :unprocessable_entity alias (so like render :new, status: :unprocessable_entity). This seems to work well with and without JavaScript and inside or outside of a Turbo frame.

[]{#use-data-turbo-false-to-break-out-of-a-frame}

If you have a link inside of a frame that you want to bypass the default Turbo behavior and trigger a full page reload, include the data-turbo="false" attribute (or use data: { turbo: false } in your helper).

Update from good guy Leo: you can also use target="_top" to load all the content from the response without doing a full page reload, which seems (to me, David) what you typically want except under specific circumstances.

[]{#use-requestSubmit-to-trigger-a-turbo-form-submission-via-javaScript}

If you have some JavaScript (say in a Stimulus controller) that you want to trigger a form submission with a Turbo response, you can't use the usual submit() method. This discussion thread sums it up well:

It turns out that the turbo-stream mechanism listens for form submission events, and for some reason the submit() function does not emit a form submission event. That means that it'll bring back a normal HTML response. That said, it looks like there's another method, requestSubmit() which does issue a submit event. Weird stuff from JavaScript land.

So, yeah, use requestSubmit() (i.e. this.formTarget.requestSubmit()) and you're golden (except in Safari, where you might need this polyfill).

[]{#loading-the-same-url-multiple-times-in-a-turbo-frame}

I hit an interesting issue with a form inside a frame: in a listing of comments, I set it up where you could click an edit link, and the content would be swapped out for an edit form using a Turbo Frame. Update and save your comment, and the new content would render. Issue was, if you hit the edit link again, nothing would happen. Turns out, a Turbo frame won't reload a URL if it thinks it already has the contents of that URL (which it tracks in a src attribute).

The solution I found was to append a timestamp to the URL to ensure it's always unique. Works like a charm.

Update from good guy Joshua: this has been fixed an a recent update.

[Learn More]{.util-breadcrumb-md .mb-8 .group-hover:translate-y-20 .group-hover:opacity-0 .transition-all .ease-in-out .duration-500}{.relative .flex .group .flex-col .p-32 .md:p-40 .lg:p-64 .z-10}

We're hiring Application Developers. Learn more and introduce yourself. {#were-hiring-application-developers.-learn-more-and-introduce-yourself. .text-20 .md:text-24 .lg:text-32 .font-bold .leading-[170%] .group-hover:-translate-y-20 .transition-transform .ease-in-out .duration-500}

{.rect-icon-md .self-end .mt-16 .group-hover:-translate-y-20 .transition-all .ease-in-out .duration-500}

These small issues aside, Turbo has been a BLAST to work with and has allowed us to easily build a highly dynamic app that works surprisingly well even with JavaScript disabled. We're excited to see how this technology develops.