![Real-Time Updates in a Ruby on Rails Dashboard with Hotwire](https://unagisoftware.com/wp-content/uploads/2025/02/Medium-Nico-1-1280x720.jpg)
Let’s imagine we have a dashboard with important data for our business (e.g., number of active users, number of sales, server status). These numbers change over time, and we don’t want to reload the page to see the updates.
There are many ways to approach this, like but one simple solution is using Turbo Frames and automatically reloading them with the reload
function for each frame.
Dashboard
Let’s start creating the view for our dashboard. We can create three Turbo Frames with eager loading, one for each stat:
<h1>Dashboard</h1>
<%= turbo_frame_tag "sales", src: reports_sales_path do %>
<p>Loading sales...</p>
<% end %>
<%= turbo_frame_tag "active_users", src: reports_users_path do %>
<p>Loading users...</p>
<% end %>
<%= turbo_frame_tag "servers", src: reports_servers_path do %>
<p>Checking servers...</p>
<% end %>
Each report might return something like this
<%= turbo_frame_tag "sales" do %>
<svg ...>
<p>Today sales</p>
<p><%= number_with_delimiter @sales %></p>
<% end %>
![](https://miro.medium.com/v2/resize:fit:1120/1*jPtJxNP_H5tNQE8OhSGInA.png)
Now, let’s build a Stimulus controller that reloads each Turbo Frame every 3 seconds:
// app/javascript/controllers/reloader_controller.js
export default class extends Controller {
connect() {
setInterval(() => {
this.element.reload();
}, 3000);
}
}
And finally associate the controller with each Turbo Frame
<%= turbo_frame_tag "sales", src: reports_sales_path,
data: { controller: "reloader" } do %>
<p>Loading sales...</p>
<% end %>
<%= turbo_frame_tag "active_users", src: reports_users_path,
data: { controller: "reloader" } do %>
<p>Loading users...</p>
<% end %>
<%= turbo_frame_tag "servers", src: reports_servers_path,
data: { controller: "reloader" } do %>
<p>Checking servers...</p>
<% end %>
With this, each controller will set an interval to request the same path every 3 seconds upon connection 💪.
![](https://miro.medium.com/v2/resize:fit:1120/1*jDuBVJ-m_n95Rkm9bQNgKw.gif)
Custom interval
To make things more flexible, we can add a value to the controller to customize the interval time. This way, we can check the number of active users more frequently than the server status, for example:
// app/javascript/controllers/reloader_controller.js
export default class extends Controller {
static values = { interval: Number };
connect() {
setInterval(() => {
this.element.reload();
}, this.intervalValue);
}
}
<%= turbo_frame_tag "sales", src: reports_sales_path,
data: { controller: "reloader", reloader_interval_value: 3_000 } do %>
<p>Loading sales...</p>
<% end %>
<%= turbo_frame_tag "active_users", src: reports_users_path,
data: { controller: "reloader", reloader_interval_value: 5_000 } do %>
<p>Loading users...</p>
<% end %>
<%= turbo_frame_tag "servers", src: reports_servers_path,
data: { controller: "reloader", reloader_interval_value: 10_000 } do %>
<p>Checking servers...</p>
<% end %>