# Ruby on Rails 7: Hotwire e Turbo para Aplicacoes Reativas > Guia completo de Hotwire e Turbo no Rails 7. Aprenda a construir aplicacoes reativas sem escrever JavaScript com 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 --- O Rails 7 revolucionou o desenvolvimento web ao integrar o Hotwire por padrao. Essa stack permite construir aplicacoes altamente reativas sem escrever uma unica linha de JavaScript personalizado. Turbo Drive, Turbo Frames e Turbo Streams substituem as abordagens tradicionais de SPA com uma filosofia de "HTML pelo fio". > **Por que Hotwire?** > > O Hotwire reduz drasticamente a complexidade do frontend. Nao e necessario React ou Vue para interfaces dinamicas: o servidor envia HTML pronto para uso, e o Turbo cuida das atualizacoes do DOM automaticamente. ## Entendendo a Arquitetura do Hotwire O Hotwire consiste em tres tecnologias complementares que trabalham juntas para entregar uma experiencia de usuario fluida sem a complexidade tipica dos frameworks JavaScript. **Turbo Drive** acelera a navegacao interceptando cliques em links e envios de formularios. Em vez de recarregar a pagina inteira, apenas o conteudo do `` e substituido, preservando o contexto de JavaScript e CSS. **Turbo Frames** decompoe as paginas em secoes independentes. Cada frame pode ser atualizado separadamente, permitindo interacoes direcionadas sem afetar o restante da pagina. **Turbo Streams** permitem atualizacoes em tempo real via WebSocket ou em resposta a requisicoes HTTP. Oito acoes CRUD estao disponiveis para manipulacao declarativa do DOM. ```ruby # Gemfile # Installing Turbo Rails (included by default in Rails 7+) gem 'turbo-rails' ``` Para projetos existentes, a instalacao requer apenas um 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" ``` ## Configuracao Inicial do Turbo Drive O Turbo Drive vem habilitado por padrao no Rails 7. Toda a navegacao automaticamente se torna "turbo" sem configuracao adicional. O comportamento pode ser personalizado por meio de atributos data. ```erb <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %>
<%= yield %> ``` O Turbo Drive pode ser desativado em links ou formularios especificos 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 do Turbo Drive** > > O Turbo Drive armazena em cache as paginas visitadas. O atributo `data-turbo-track="reload"` nos assets forca um recarregamento completo se os arquivos CSS/JS mudarem. ## Turbo Frames para Atualizacoes Direcionadas Turbo Frames definem zonas da pagina que se atualizam de forma independente. Cada frame possui um identificador unico e so responde a respostas que contenham um frame correspondente. ```erb

Messages

<%= render @messages %>
<%= link_to "Load more", messages_path(page: @next_page) %>
<%= render "form", message: Message.new %> ``` A resposta do servidor deve conter um frame com o mesmo identificador para que a atualizacao funcione. ```erb

<%= message.content %>

<%= link_to "Edit", edit_message_path(message) %> <%= button_to "Delete", message_path(message), method: :delete %>
``` ### Carregamento Lazy com Turbo Frames Os frames podem carregar seu conteudo de forma assincrona usando o atributo `src`. O conteudo inicial e exibido durante o carregamento. ```erb

Dashboard

Loading statistics...

Loading notifications...

<%= render "activity/placeholder" %> ``` O controller responde com uma view contendo apenas o frame solicitado. ```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 para Atualizacoes em Tempo Real Turbo Streams oferece oito acoes para manipulacao do DOM: `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after` e `morph`. Essas acoes podem ser acionadas via resposta HTTP ou 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 ``` ### Templates Dedicados de Turbo Stream Para respostas mais complexas, um template `.turbo_stream.erb` oferece maior flexibilidade. ```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 da Resposta** > > As respostas de Turbo Stream devem ter o content-type `text/vnd.turbo-stream.html`. O Rails trata isso automaticamente com `respond_to` e o formato `turbo_stream`. ## Broadcasting em Tempo Real com Action Cable Turbo Streams realmente brilha com o broadcasting via WebSocket. Os usuarios recebem atualizacoes instantaneamente sem 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 ``` A view se inscreve no stream correspondente com o 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 Assincrono para Operacoes Pesadas Para evitar bloqueio de requisicoes, o broadcasting pode ser realizado em segundo plano. ```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 ``` ## Padroes Avancados com Turbo ### Edicao Inline de Formularios Um padrao comum envolve substituir conteudo estatico por um formulario de edicao 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 %>
``` ### Navegacao Fora do Frame Pai Por padrao, os links em um frame permanecem dentro desse frame. O atributo `data-turbo-frame` permite apontar para outro frame ou para a pagina inteira. ```erb ``` ```erb
<%= yield %>
``` > **Depuracao do Turbo** > > Em desenvolvimento, abra o console JavaScript e digite `Turbo.setProgressBarDelay(0)` para ver a barra de progresso imediatamente. `Turbo.session.drive = false` desativa o Turbo Drive temporariamente. ## Tratamento de Erros e Estados de Carregamento Uma boa UX exige o tratamento de estados de carregamento e erros de rede. ```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") } } ``` ### Tratamento de Erros do Servidor ```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 ``` ## Otimizacao de Performance Varias tecnicas garantem aplicacoes Turbo com bom desempenho. ```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 %> ``` ## Conclusao Hotwire e Turbo transformam o desenvolvimento em Rails ao eliminar a complexidade dos frameworks JavaScript tradicionais. Turbo Drive acelera a navegacao, Turbo Frames permitem atualizacoes direcionadas, e Turbo Streams oferece poderosas capacidades em tempo real. ### Checklist para Comecar com Hotwire - Usar Rails 7+ para integracao nativa com Hotwire - Compreender os tres componentes: Drive, Frames e Streams - Identificar zonas da pagina que se beneficiam de Turbo Frames - Usar `respond_to` com `format.turbo_stream` nos controllers - Implementar broadcasting para funcionalidades em tempo real - Combinar com Stimulus para interacoes JavaScript simples Essa abordagem de "HTML pelo fio" permite construir aplicacoes modernas e reativas mantendo a simplicidade e produtividade que tornam o Ruby on Rails tao poderoso. O resultado: menos codigo para manter, excelente desempenho e uma experiencia de desenvolvimento otima. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/ruby-on-rails/ruby-on-rails-7-hotwire-turbo