Hotwire: Exploring Turbo Rails

Arunkumar Ry
Railsfactory
Published in
5 min readApr 25, 2024

Overview

In this blog post, we will take a high-level overview of what is hotwire and how it can help to create interactive and dynamic rails web applications with minimal effort.

Components in Hotwire

Turbo Drive

It is an enhanced version of Turbolinks. Turbo Drive makes navigating web pages faster by replacing full-page reloads with partial updates, resulting in a smoother user experience.

Turbo Frames

Turbo Frames allow you to isolate parts of a page that can be updated separately, making it easy to create dynamic user interfaces.

Turbo Streams

Turbo Streams enable real-time updates to pages by streaming changes directly to the client without manual JavaScript coding.

Stimulus

It is a JavaScript framework that can make the web page more interactive and responsive with limited JavaScript code.

Hotwire simplifies building interactive and dynamic web applications within the Rails 7 ecosystem by providing built-in Hotwire support with tools like Turbo Drive, Turbo Frames, Turbo Streams, and Stimulus.

Deep Drive

Let’s deep dive into each of the components and look at how they work in a rails application.

Turbo Drive

We need to include the Turbo Drive tags in the < head> section of the rails layout file as shown below.

<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<!-- ... other meta tags ... -->
<%= turbo_include_tags %>
</head>
<body>
<%= yield %>
</body>
</html>

We can use “link_to” helpers for links. Turbo Drive will intercept these links and use its navigation.

<%= link_to "Posts", posts_path %>

Turbo Drive will automatically fetch and replace the content of the <body> tag without a full page reload whenever the link is clicked. Below is the “posts_controller” which handles post actions.

#app/controllers/posts_controller.rb
def index
@posts = Post.all
end

It will render the posts index page to list all the posts without reloading the other content on the page.

<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
<%= render @posts %>

Turbo Frames

In the rails view file, we can wrap any part of the page with a turbo frame block with a specific ID. This helps in the isolation of different parts of the page.

<%= turbo_frame_tag "main_content" do %>
<%= yield %>
<% end %>

In the above code “main_content” is the turbo frame which acts independently and with the help of this, we can manipulate the content inside the “main_content” frame without affecting the rest of the page.

We can have multiple turbo frames inside a page. For example:

<!-- app/views/layouts/application.html.erb -->
<%= turbo_frame_tag "container" do %>
<%= turbo_frame_tag "sidebar" do %>
<%= render partial: "layouts/shared/sidebar" %>
<% end %>
<!-- Main Content -->
<main>
<%= turbo_frame_tag "main_content" do %>
<%= yield %>
<% end %>
</main>
<% end %>

In the above code snippet. We can see there are multiple turbo frames nested within each other. This helps in the isolation of the components. If there is a change in “main_content” only that part reloads without reloading the whole page and keeps the other frames as it is.

Turbo Streams

They work by streaming changes to the view via controller and updating specific elements or frames on a web page, creating a dynamic and responsive user experience.

In the rails controller, we can use turbo stream to send real-time updates to the turbo frame along with a few other parameters if necessary.

For example:

def create
@feed = Feed.find_or_initialize_by(feed_params)
if @feed.save
respond_to do |format|
format.turbo_stream { render turbo_stream: turbo_stream.replace("main_content", template: "feeds/show") }
end
end
end

In the above example, as shown we can replace turbo frame content(“main_content”) with a template by rendering a turbo stream with an action “replace”.

There are different turbo stream actions we can use:

  • Append:- For adding new content to an existing element on the page without affecting other elements.
  • Replace:- For replacing the content of a target element with new content provided in the Turbo Stream.
  • Update:- For modifying the attributes or properties of an existing element on the page.
  • Remove:- For removing a specific target element from the page.
  • Prepend:- For inserting new content immediately after the target element.
  • After:- For inserting new content immediately after the target element.

Broadcasting

In Rails, we can broadcast Turbo Streams to models using Action Cable. This means you can send real-time updates to specific models and have those updates reflected in the corresponding Turbo Streams.

class Message < ApplicationRecord
belongs_to :group
after_create_commit -> { broadcast_append_to group }
end

In the above example, we have ‘group’ and ‘message’ models with one-to-many associations (Messages belong to the group).

This is what the group view looks like:

<%= turbo_frame_tag "group" do %>
<%= render @group.messages %>
<% end %>

In this case, after the message is created we have a “broadcast_append_to” group in an “after_create_commit” callback hook. It will send the update through action cable and append the new message to the existing group message list without affecting other messages.

We have different types of broadcasting actions like -

after_update_commit { broadcast_replace }
after_create_commit { broadcast_append_later_to('group') }

To broadcast all actions related to the particles model class we can just add “broadcasts”.

class Group < ApplicationRecord
has_many :messages
broadcasts
end

This will take care of all actions related to group objects within the turbo frame.

Create

After a new record for the model Group is created, Rails will automatically broadcast a Turbo Streams message to all subscribers, informing them about the new record.

Update

When a record in ‘Group’ is updated, Rails will automatically broadcast a Turbo Streams message to all subscribers, informing them about the changes made to the record.

Destroy

After a record in ‘Group’ is destroyed (deleted), Rails will automatically broadcast a Turbo Streams message to all subscribers, informing them about the deletion of the record.

NOTE — This article serves as an introductory guide to understanding and implementing Turbo in Rails. It covers the basics and provides a foundation for integrating Turbo into your Rails applications.

For a deeper dive into Turbo and to explore more advanced implementation techniques, we encourage you to experiment with it firsthand. Dive into your Rails projects, explore the documentation, and leverage the power of Turbo to enhance the interactivity and responsiveness of your applications.

--

--