Upgrade Rails 6.1 Application to Hotwire
The new magic “Hotwire” is released. Here are some notes on how to use it in an existing Rails application. If you look at the hotwired-rails, you wil notice that it basically contains two gems: turbo-rails and stimulus-rails. And by reading these two gems, you will notice that turbo-rails is a upgraded version of turbolinks, and stimulus-rails is actually stimulus npm package. If you use webpacker for javascript, you do not need to run turbo:install
and stimulus:install
. Therefore, we only need to do two things to get hotwire work in existing Rails application:
- upgrade stimulus.js from 1.1.1 to 2.0.0
- replace turbolinks with turbo
Upgrade stimulus.js to 2.0.0
This part is easy. Just run yarn add stimulus
. Start your application and look at the javascript console in web browser. It will remind you to replace data-target
with data-[controller name]-target
. If you use data: {target: 'hello.content'}
before, it needs to become data: {hello_target: 'content'}
. Note the underscore vs hyphen.
Replace turbolinks with turbo
There are detailed instructions in installing turbo and removing turbolinks in turbo-rails . Just follow it. In short, replace turbolinks
with turbo
in Gemfile and install npm packages through yarn.
If you do not yet plan to use all the fancy functions of turbo, you only need to read Turbo Drive, which is very similar to turbolinks.
In short, data-turbolinks-track
becomes data-turbo-track
; data-turbolinks="false"
becomes data-turbo="false"
.
That’s it. Test your Rails application and see if it breaks anything. If not, you can take advantages of what hotwire (turbo + stimulus) can offer, such as Turbo Frames and Streams.
Rails unobtrusive scripting adapter
If you suddenly realize that all links with data-method
do not work, you are not alone. By default, Rails create links to destroy with this style. If you remove @rails/ujs
during the installation of turbo-rails, data-method
will not work. There are two solutions:
- Add
@rails/ujs
back with yarn. I do not know any side effect for now. - Use
button_to
instead oflink_to
.
Render in Controller
Traditional form validation use render in controller when validation failed. It will not work with Turbo for now.
Use case #1 — tabs
It is quite common to have tabs, but how to implement depends. One is to have Javascript show and hide content according to selected tab (client-side). The other is to make several web pages corresponding to each tab (server-side). Now, Turbo frame allows you to use server-side approach, but minimize the page loading. Just put tab content (and probably tabs) under turbo-frame
tag. That is probably the easiest way to use Turbo frame.
Use case #2 — modal
Some css-based modal use class to show and hide a modal. It is less flexible. Now, you can actually use Turbo frame to share the same modal by injecting content into an application-level modal. Just define an empty Turbo frame in application layout and replace it when needed. You probably need some Javascript if there are some interactive elements in the modal. A trivial issue I found is that Turbo will cache pages, which sometimes include the modal. When the cache is used by Turbo as preview before the real content is fetched, the modal will briefly show up. To fix it, I add this at application-level javscript:
document.addEventListener("turbo:before-cache", function() {
// Remove modal so that it will be not cached by Turbo
let modal_element = document.getElementById("app-modal");
if (modal_element) {
modal_element.innerHTML = "";
}
})