# Ruby on Rails 7: Hotwire e Turbo per Applicazioni Reattive > Guida completa a Hotwire e Turbo in Rails 7. Costruire applicazioni reattive senza scrivere JavaScript con Turbo Drive, Frames e Streams. - Published: 2026-01-11 - Updated: 2026-04-07 - Author: SharpSkill - Tags: ruby on rails, hotwire, turbo, turbo frames, turbo streams - Reading time: 12 min --- Rails 7 ha rivoluzionato lo sviluppo web integrando Hotwire di default. Questo stack consente di costruire applicazioni altamente reattive senza scrivere una singola riga di JavaScript personalizzato. Turbo Drive, Turbo Frames e Turbo Streams sostituiscono gli approcci SPA tradizionali con una filosofia "HTML via cavo". > **Perche Hotwire?** > > Hotwire riduce drasticamente la complessita del frontend. Non servono React o Vue per interfacce dinamiche: il server invia HTML pronto all'uso e Turbo gestisce automaticamente gli aggiornamenti del DOM. ## Comprendere l'Architettura di Hotwire Hotwire consiste in tre tecnologie complementari che lavorano insieme per offrire un'esperienza utente fluida senza la tipica complessita dei framework JavaScript. **Turbo Drive** accelera la navigazione intercettando i clic sui link e gli invii dei form. Invece di ricaricare l'intera pagina, viene sostituito solo il contenuto del ``, preservando il contesto JavaScript e CSS. **Turbo Frames** scompongono le pagine in sezioni indipendenti. Ogni frame puo essere aggiornato separatamente, consentendo interazioni mirate senza influire sul resto della pagina. **Turbo Streams** consentono aggiornamenti in tempo reale tramite WebSocket o in risposta a richieste HTTP. Otto azioni CRUD sono disponibili per la manipolazione dichiarativa del DOM. ```ruby # Gemfile # Installing Turbo Rails (included by default in Rails 7+) gem 'turbo-rails' ``` Per i progetti esistenti, l'installazione richiede un solo comando. ```bash # installation.sh # Installing Turbo in an existing Rails project rails turbo:install # Verify the JavaScript import is present cat app/javascript/application.js # Should contain: import "@hotwired/turbo-rails" ``` ## Configurazione Iniziale di Turbo Drive Turbo Drive e abilitato di default in Rails 7. Tutta la navigazione diventa automaticamente "turbo" senza configurazione aggiuntiva. Il comportamento puo essere personalizzato tramite attributi data. ```erb <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %>
<%= yield %> ``` Turbo Drive puo essere disabilitato su link o form specifici quando necessario. ```erb <%= link_to "Dashboard", dashboard_path %> <%= link_to "Download PDF", export_path, data: { turbo: false } %> <%= form_with model: @document, data: { turbo: false } do |f| %> <%= f.file_field :attachment %> <%= f.submit "Upload" %> <% end %> <%= link_to "Delete", item_path(@item), data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %> ``` > **Cache di Turbo Drive** > > Turbo Drive memorizza nella cache le pagine visitate. L'attributo `data-turbo-track="reload"` sugli asset forza un ricaricamento completo se i file CSS/JS cambiano. ## Turbo Frames per Aggiornamenti Mirati I Turbo Frames definiscono zone della pagina che si aggiornano in modo indipendente. Ogni frame ha un identificatore univoco e risponde solo alle risposte contenenti un frame corrispondente. ```erb

Messages

<%= render @messages %>
<%= link_to "Load more", messages_path(page: @next_page) %>
<%= render "form", message: Message.new %> ``` La risposta del server deve contenere un frame con lo stesso identificatore affinche l'aggiornamento funzioni. ```erb

<%= message.content %>

<%= link_to "Edit", edit_message_path(message) %> <%= button_to "Delete", message_path(message), method: :delete %>
``` ### Caricamento Lazy con Turbo Frames I frame possono caricare il loro contenuto in modo asincrono usando l'attributo `src`. Il contenuto iniziale viene visualizzato durante il caricamento. ```erb

Dashboard

Loading statistics...

Loading notifications...

<%= render "activity/placeholder" %> ``` Il controller risponde con una view contenente solo il frame richiesto. ```ruby # app/controllers/dashboard_controller.rb class DashboardController < ApplicationController def stats @user_count = User.count @message_count = Message.count @active_today = User.where("last_seen_at > ?", 24.hours.ago).count # Partial rendering for the frame render partial: "dashboard/stats" end end ``` ```erb

<%= @user_count %>

Users

<%= @message_count %>

Messages

<%= @active_today %>

Active today

``` ## Turbo Streams per Aggiornamenti in Tempo Reale Turbo Streams offre otto azioni per la manipolazione del DOM: `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after` e `morph`. Queste azioni possono essere attivate tramite risposta HTTP o WebSocket. ```ruby # app/controllers/messages_controller.rb class MessagesController < ApplicationController def create @message = current_user.messages.build(message_params) respond_to do |format| if @message.save # Turbo Stream response to add the message format.turbo_stream do render turbo_stream: [ turbo_stream.prepend("messages", @message), turbo_stream.update("message_count", partial: "messages/count"), turbo_stream.replace("new_message", partial: "messages/form", locals: { message: Message.new }) ] end format.html { redirect_to messages_path, notice: "Message created" } else format.turbo_stream do render turbo_stream: turbo_stream.replace( "new_message", partial: "messages/form", locals: { message: @message } ) end format.html { render :new, status: :unprocessable_entity } end end end def destroy @message = Message.find(params[:id]) @message.destroy respond_to do |format| # Removal with animation format.turbo_stream { render turbo_stream: turbo_stream.remove(@message) } format.html { redirect_to messages_path, notice: "Message deleted" } end end end ``` ### Template Dedicati per Turbo Stream Per risposte piu complesse, un template `.turbo_stream.erb` offre maggiore flessibilita. ```erb <%= turbo_stream.prepend "messages" do %> <%= render @message %> <% end %> <%= turbo_stream.update "message_count" do %> <%= Message.count %> messages <% end %> <%= turbo_stream.replace "new_message" do %> <%= render "form", message: Message.new %> <% end %> <%= turbo_stream.prepend "flash_messages" do %>
Message sent successfully!
<% end %> ``` > **Formato della Risposta** > > Le risposte Turbo Stream devono avere il content-type `text/vnd.turbo-stream.html`. Rails gestisce questo automaticamente con `respond_to` e il formato `turbo_stream`. ## Broadcasting in Tempo Reale con Action Cable Turbo Streams eccelle davvero con il broadcasting via WebSocket. Gli utenti ricevono aggiornamenti istantaneamente senza polling. ```ruby # app/models/message.rb class Message < ApplicationRecord belongs_to :room belongs_to :author, class_name: "User" # Automatic broadcast after creation after_create_commit do broadcast_append_to( room, target: "messages", partial: "messages/message", locals: { message: self } ) end # Broadcast after update after_update_commit do broadcast_replace_to( room, target: dom_id(self), partial: "messages/message", locals: { message: self } ) end # Broadcast after deletion after_destroy_commit do broadcast_remove_to(room, target: dom_id(self)) end end ``` La view si iscrive allo stream corrispondente con l'helper `turbo_stream_from`. ```erb

<%= @room.name %>

<%= turbo_stream_from @room %>
<%= render @room.messages.order(created_at: :asc) %>
<%= form_with model: [@room, Message.new], id: "new_message" do |f| %> <%= f.text_area :content, placeholder: "Your message..." %> <%= f.submit "Send" %> <% end %> ``` ### Broadcasting Asincrono per Operazioni Pesanti Per evitare di bloccare le richieste, il broadcasting puo essere eseguito in background. ```ruby # app/models/report.rb class Report < ApplicationRecord belongs_to :user after_create_commit :generate_async private def generate_async GenerateReportJob.perform_later(self) end end ``` ```ruby # app/jobs/generate_report_job.rb class GenerateReportJob < ApplicationJob queue_as :default def perform(report) # Simulating a long operation report.update!(status: "processing") # Notify user of start report.broadcast_replace_to( report.user, :reports, target: dom_id(report), partial: "reports/report" ) # Generate the report result = ReportGenerator.new(report).generate report.update!(content: result, status: "completed") # Notify user of completion report.broadcast_replace_to( report.user, :reports, target: dom_id(report), partial: "reports/report" ) end end ``` ## Pattern Avanzati con Turbo ### Modifica Inline dei Form Un pattern comune consiste nel sostituire il contenuto statico con un form di modifica inline. ```erb
<%= task.content %>
<%= link_to "Edit", edit_task_path(task) %> <%= button_to "Delete", task_path(task), method: :delete, data: { turbo_confirm: "Delete this task?" } %>
``` ```erb <%= form_with model: @task do |f| %> <%= f.text_field :content, autofocus: true %>
<%= f.submit "Save" %> <%= link_to "Cancel", task_path(@task) %>
<% end %>
``` ### Navigazione Fuori dal Frame Padre Per impostazione predefinita, i link in un frame rimangono all'interno di quel frame. L'attributo `data-turbo-frame` consente di puntare a un altro frame o all'intera pagina. ```erb ``` ```erb
<%= yield %>
``` > **Debug di Turbo** > > In sviluppo, aprire la console JavaScript e digitare `Turbo.setProgressBarDelay(0)` per visualizzare immediatamente la barra di avanzamento. `Turbo.session.drive = false` disabilita temporaneamente Turbo Drive. ## Gestione degli Errori e Stati di Caricamento Una buona UX richiede la gestione degli stati di caricamento e degli errori di rete. ```erb <%= form_with model: @model, data: { controller: "form-loading", action: "turbo:submit-start->form-loading#disable turbo:submit-end->form-loading#enable" } do |f| %> <%= yield f %> <% end %> ``` ```javascript // app/javascript/controllers/form_loading_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["submit", "text", "spinner"] disable() { this.submitTarget.disabled = true this.textTarget.classList.add("hidden") this.spinnerTarget.classList.remove("hidden") } enable() { this.submitTarget.disabled = false this.textTarget.classList.remove("hidden") this.spinnerTarget.classList.add("hidden") } } ``` ### Gestione degli Errori del Server ```ruby # app/controllers/application_controller.rb class ApplicationController < ActionController::Base rescue_from ActiveRecord::RecordNotFound do |exception| respond_to do |format| format.turbo_stream do render turbo_stream: turbo_stream.replace( "main_content", partial: "shared/not_found" ) end format.html { render "errors/not_found", status: :not_found } end end end ``` ## Ottimizzazione delle Prestazioni Diverse tecniche assicurano applicazioni Turbo performanti. ```ruby # app/controllers/messages_controller.rb class MessagesController < ApplicationController # Avoid N+1 queries with eager loading def index @messages = Message.includes(:author, :room) .order(created_at: :desc) .page(params[:page]) end # Fragment caching for static elements def show @message = Message.find(params[:id]) fresh_when @message end end ``` ```erb <% cache message do %>
<%= message.content %> By <%= message.author.name %>
<% end %> ``` ## Conclusione Hotwire e Turbo trasformano lo sviluppo Rails eliminando la complessita dei framework JavaScript tradizionali. Turbo Drive accelera la navigazione, Turbo Frames consentono aggiornamenti mirati, e Turbo Streams offre potenti capacita in tempo reale. ### Checklist per Iniziare con Hotwire - Utilizzare Rails 7+ per l'integrazione Hotwire integrata - Comprendere i tre componenti: Drive, Frames e Streams - Identificare le zone della pagina che beneficiano dei Turbo Frames - Utilizzare `respond_to` con `format.turbo_stream` nei controller - Implementare il broadcasting per le funzionalita in tempo reale - Combinare con Stimulus per interazioni JavaScript semplici Questo approccio "HTML via cavo" consente di costruire applicazioni moderne e reattive mantenendo la semplicita e la produttivita che rendono Ruby on Rails cosi potente. Il risultato: meno codice da mantenere, prestazioni eccellenti e un'esperienza di sviluppo ottimale. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/it/blog/ruby-on-rails/ruby-on-rails-7-hotwire-turbo