What Is Hotwire

Hotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire.

Hotwire, is a solution developed by the team behind Basecamp and Hey to develop modern, real-time web apps without writing lots of JavaScript.

turbo, stimulus, and strada are components of Hotwire but strada hasn’t been released yet. Basically iframe but for 2021.

Let’s dive into hotwire and learn how to install and use it.

Turbo

Turbo is the main component of Hotwire. We can write real-time web apps with turbo without JavaScript (not without it but dramatically reduce the amount of custom JavaScript that most web applications will need to write).

Turbo Drive, Turbo Streams, Turbo Frames and Turbo Native are complementary techniques that Turbo uses. Turbo updates web app content through using WebSockets and ActiveCable under the hood. The best part for me is that we don’t need to change anything in controller classes to use it.

Stimulus

Stimulus is a JavaScript framework, and we don’t need to change our front-end to use it.

It doesn’t seek to take over your entire front-end—in fact, it’s not concerned with rendering HTML at all. Instead, it’s designed to augment your HTML with just enough behavior to make it shine.

Turbo will handle a big portion of our needs but eventually we will use custom JavaScript code to augment it.

Now I want to show how to use the hotwire with rails.

Setup

  • First we need to add the hotwire-rails gem to our Gemfile
bundle add hotwire-rails
bundle install
  • Then install hotwire
rails hotwire:install

BTW we need redis to be running. Turbo uses redis to store its data. That’s it, let’s create a rails project.

Usage

Create a rails project named hotwire_example.

rails new hotwire_example

Make sure you follow the setup instructions.

Now generate a scaffold named Blog with the content field.

rails g scaffold Blog content:text

Now add our ActionCable broadcast channel preferences to our model. Edit Blog model. It should look something like this:

class Blog < ApplicationRecord
    after_create_commit { broadcast_append_to "blog" }
    after_destroy_commit { broadcast_remove_to "blog" }
    after_update_commit { broadcast_replace_to "blog" }
end

This is pretty self explanatory.

Now we need to edit views/blogs/index.html.erb like this

<h1>Blogs</h1>
<%= turbo_stream_from "blog" %>
<%= turbo_frame_tag "blogs" do %>
<%= render @blogs %>
<% end %>

<br>

<%= link_to 'New Blog', new_blog_path %>

Here we use turbo_stream_from, which tells turbo where we get updates. It should be the same thing we used in our model. Then we create our turbo_frame to mark which parts we want to update in our app.

Here is our blog partial:(_blog.html.erb)

<%= turbo_frame_tag dom_id(blog) do %>
<%= blog.content %><br>
<%= link_to 'Show', blog %>
<%= link_to 'Edit', edit_blog_path(blog) %>
<%= link_to 'Destroy', blog, method: :delete, data: { confirm: 'Are you sure?' } %>
<br><br>
<% end %>

We are using dom_id here for readable ids for blog entries. Now we need to update our form partial (_form.html.erb) by just adding turbo_frame_tag.

<%= turbo_frame_tag dom_id(@blog) do %>
<%= form_with(model: blog) do |form| %>
  <% if blog.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(blog.errors.count, "error") %> prohibited this blog from being saved:</h2>

      <ul>
        <% blog.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :content %>
    <%= form.text_area :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
<% end %>

That’s it, let’s start our rails server and check if it works.

rails s # don't forget to run redis if it is not running

Here is the gif of working version.