# Ruby on Rails 7: Hotwire und Turbo fuer reaktive Anwendungen > Vollstaendiger Leitfaden zu Hotwire und Turbo in Rails 7. Reaktive Anwendungen ohne JavaScript mit Turbo Drive, Frames und Streams entwickeln. - 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 hat die Webentwicklung revolutioniert, indem Hotwire standardmaessig integriert wurde. Dieser Stack ermoeglicht es, hochreaktive Anwendungen zu erstellen, ohne eine einzige Zeile benutzerdefinierten JavaScript-Code zu schreiben. Turbo Drive, Turbo Frames und Turbo Streams ersetzen traditionelle SPA-Ansaetze durch eine "HTML ueber den Draht"-Philosophie. > **Warum Hotwire?** > > Hotwire reduziert die Frontend-Komplexitaet drastisch. Kein React oder Vue fuer dynamische Oberflaechen noetig: Der Server sendet gebrauchsfertiges HTML, und Turbo uebernimmt die DOM-Aktualisierungen automatisch. ## Die Hotwire-Architektur verstehen Hotwire besteht aus drei komplementaeren Technologien, die zusammenarbeiten, um eine fluessige Benutzererfahrung ohne die typische JavaScript-Framework-Komplexitaet zu bieten. **Turbo Drive** beschleunigt die Navigation, indem Link-Klicks und Formularuebermittlungen abgefangen werden. Statt die gesamte Seite neu zu laden, wird nur der Inhalt des `` ersetzt, wobei der JavaScript- und CSS-Kontext erhalten bleibt. **Turbo Frames** zerlegen Seiten in unabhaengige Abschnitte. Jeder Frame kann separat aktualisiert werden, was gezielte Interaktionen ermoeglicht, ohne den Rest der Seite zu beeinflussen. **Turbo Streams** ermoeglichen Echtzeit-Aktualisierungen ueber WebSocket oder als Antwort auf HTTP-Anfragen. Acht CRUD-Aktionen stehen fuer deklarative DOM-Manipulation zur Verfuegung. ```ruby # Gemfile # Installing Turbo Rails (included by default in Rails 7+) gem 'turbo-rails' ``` Fuer bestehende Projekte erfordert die Installation nur einen Befehl. ```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" ``` ## Initiale Turbo Drive Konfiguration Turbo Drive ist in Rails 7 standardmaessig aktiviert. Alle Navigation wird automatisch zu "Turbo", ohne zusaetzliche Konfiguration. Das Verhalten kann ueber Data-Attribute angepasst werden. ```erb <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %>
<%= yield %> ``` Turbo Drive kann bei Bedarf fuer bestimmte Links oder Formulare deaktiviert werden. ```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?" } %> ``` > **Turbo Drive Cache** > > Turbo Drive speichert besuchte Seiten im Cache. Das Attribut `data-turbo-track="reload"` bei Assets erzwingt ein vollstaendiges Neuladen, wenn sich CSS/JS-Dateien aendern. ## Turbo Frames fuer gezielte Aktualisierungen Turbo Frames definieren Seitenbereiche, die unabhaengig aktualisiert werden. Jeder Frame hat einen eindeutigen Bezeichner und reagiert nur auf Antworten, die einen passenden Frame enthalten. ```erb

Messages

<%= render @messages %>
<%= link_to "Load more", messages_path(page: @next_page) %>
<%= render "form", message: Message.new %> ``` Die Serverantwort muss einen Frame mit demselben Bezeichner enthalten, damit die Aktualisierung funktioniert. ```erb

<%= message.content %>

<%= link_to "Edit", edit_message_path(message) %> <%= button_to "Delete", message_path(message), method: :delete %>
``` ### Lazy Loading mit Turbo Frames Frames koennen ihren Inhalt asynchron ueber das `src`-Attribut laden. Der initiale Inhalt wird waehrend des Ladens angezeigt. ```erb

Dashboard

Loading statistics...

Loading notifications...

<%= render "activity/placeholder" %> ``` Der Controller antwortet mit einer View, die nur den angeforderten Frame enthaelt. ```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 fuer Echtzeit-Aktualisierungen Turbo Streams bieten acht Aktionen zur DOM-Manipulation: `append`, `prepend`, `replace`, `update`, `remove`, `before`, `after` und `morph`. Diese Aktionen koennen ueber HTTP-Antwort oder WebSocket ausgeloest werden. ```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 ``` ### Dedizierte Turbo Stream Templates Fuer komplexere Antworten bietet ein `.turbo_stream.erb`-Template mehr Flexibilitaet. ```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 %> ``` > **Antwortformat** > > Turbo Stream-Antworten muessen den Content-Type `text/vnd.turbo-stream.html` haben. Rails handhabt dies automatisch mit `respond_to` und dem `turbo_stream`-Format. ## Echtzeit-Broadcasting mit Action Cable Turbo Streams entfalten ihre volle Staerke beim WebSocket-Broadcasting. Benutzer erhalten Aktualisierungen sofort ohne 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 ``` Die View abonniert den entsprechenden Stream mit dem `turbo_stream_from`-Helper. ```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 %> ``` ### Asynchrones Broadcasting fuer aufwendige Operationen Um Anfragen nicht zu blockieren, kann das Broadcasting im Hintergrund durchgefuehrt werden. ```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 ``` ## Fortgeschrittene Muster mit Turbo ### Inline-Formular-Bearbeitung Ein gaengiges Muster ersetzt statischen Inhalt durch ein Inline-Bearbeitungsformular. ```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 %>
``` ### Navigation ausserhalb des uebergeordneten Frames Standardmaessig bleiben Links in einem Frame innerhalb dieses Frames. Das Attribut `data-turbo-frame` ermoeglicht es, einen anderen Frame oder die gesamte Seite anzusprechen. ```erb ``` ```erb
<%= yield %>
``` > **Turbo Debugging** > > In der Entwicklungsumgebung die JavaScript-Konsole oeffnen und `Turbo.setProgressBarDelay(0)` eingeben, um die Fortschrittsleiste sofort zu sehen. `Turbo.session.drive = false` deaktiviert Turbo Drive voruebergehend. ## Fehlerbehandlung und Ladezustaende Eine gute UX erfordert die Behandlung von Ladezustaenden und Netzwerkfehlern. ```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") } } ``` ### Serverfehlerbehandlung ```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 ``` ## Performance-Optimierung Mehrere Techniken stellen performante Turbo-Anwendungen sicher. ```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 %> ``` ## Fazit Hotwire und Turbo transformieren die Rails-Entwicklung, indem sie die Komplexitaet traditioneller JavaScript-Frameworks eliminieren. Turbo Drive beschleunigt die Navigation, Turbo Frames ermoeglichen gezielte Aktualisierungen, und Turbo Streams bieten leistungsstarke Echtzeit-Faehigkeiten. ### Checkliste fuer den Einstieg mit Hotwire - Rails 7+ fuer integrierte Hotwire-Unterstuetzung verwenden - Die drei Komponenten verstehen: Drive, Frames und Streams - Seitenbereiche identifizieren, die von Turbo Frames profitieren - `respond_to` mit `format.turbo_stream` in Controllern verwenden - Broadcasting fuer Echtzeit-Features implementieren - Mit Stimulus fuer einfache JavaScript-Interaktionen kombinieren Dieser "HTML ueber den Draht"-Ansatz ermoeglicht es, moderne, reaktive Anwendungen zu erstellen und gleichzeitig die Einfachheit und Produktivitaet beizubehalten, die Ruby on Rails so leistungsstark machen. Das Ergebnis: weniger Code zu warten, hervorragende Performance und eine optimale Entwicklererfahrung. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/de/blog/ruby-on-rails/ruby-on-rails-7-hotwire-turbo