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.