2026'da Rails Turbo ve Hotwire: Gerçek Zamanlı Uygulamalar ve Mülakat Soruları

Rails geliştiricileri için Turbo 8 ve Hotwire hakkında kapsamlı bir rehber. Mimari, morphing, Turbo Streams, production kalıpları ve teknik mülakat soruları.

2026'da Rails Turbo ve Hotwire: Gerçek Zamanlı Uygulamalar ve Mülakat Soruları

Rails Turbo ve Hotwire, özel JavaScript framework'lerine gerek kalmadan web uygulamalarına gerçek zamanlı etkileşim kazandırır. 2026 ekosistemi, Turbo 8'in morphing yetenekleri ve Rails 8'in gelişmiş broadcasting mekanizmaları sayesinde olgunlaşmış durumda ve minimal kodla reaktif kullanıcı arayüzleri oluşturmak artık mümkün. Bu detaylı rehber, production kalıplarını, mülakat hazırlığını ve modern Rails uygulamaları geliştirmek için gerekli implementasyon detaylarını kapsar.

Önemli Çıkarım

Turbo 8'in broadcasts_refreshes ile morphing özelliği, tek satır Ruby koduyla gerçek zamanlı güncellemeler sağlar. Sunucu bir sinyal yayınlar, istemciler DOM'u morph eder ve scroll pozisyonu otomatik olarak korunur.

2026'da Hotwire Mimarisi

Hotwire, reaktif web deneyimleri oluşturmak için birlikte çalışan üç tamamlayıcı teknolojiden oluşur. Turbo Drive, navigasyonu ve form gönderimlerini yakalayarak tam sayfa yenilemesi olmadan AJAX üzerinden sayfa içeriğini değiştirir. Turbo Frames, güncellemeleri belirli sayfa bölgeleriyle sınırlar ve inline düzenleme ile lazy loading'i mümkün kılar. Turbo Streams, WebSocket bağlantıları veya HTTP yanıtları üzerinden granüler DOM değişiklikleri sağlar.

Mimari, HTML'in birincil yük olarak kaldığı sunucu merkezli bir model izler. JSON transfer eden ve istemci tarafında render eden SPA'ların aksine, Hotwire uygulamaları sunucu tarafında HTML render eder ve tarayıcılara stream eder. Bu yaklaşım, state yönetimini basitleştirir, SEO'yu iyileştirir ve JavaScript paket boyutlarını azaltır.

Rails 8, WebSocket desteği için Action Cable entegrasyonuyla birlikte Hotwire 2.0'ı varsayılan olarak içerir. Framework, bağlantı yönetimi, kanal abonelikleri ve broadcasting işlemlerini manuel yapılandırma gerektirmeden halleder.

Turbo Drive: Yapılandırma Gerektirmeyen SPA Navigasyonu

Turbo Drive, standart linkleri ve formları AJAX destekli etkileşimlere dönüştürür. Etkinleştirildiğinde, herhangi bir linke tıklamak bir fetch isteği tetikler, yanıt gövdesi mevcut sayfa içeriğinin yerini alır ve tarayıcı geçmişi uygun şekilde güncellenir.

ruby
# app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <%= turbo_refreshes_with method: :morph, scroll: :preserve %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

data-turbo-track: "reload" attribute'u, asset değişikliklerinin tam sayfa yenilemelerini tetiklemesini sağlayarak eski CSS veya JavaScript'i önler. turbo_refreshes_with helper'ı morphing davranışını global olarak yapılandırır, ancak sayfa bazında geçersiz kılınabilir.

Belirli linkler için Turbo Drive'ı devre dışı bırakmak data-turbo attribute'unu gerektirir:

erb
<!-- Harici linkler için Turbo'yu devre dışı bırak -->
<%= link_to "PDF İndir", document_path(@doc, format: :pdf), data: { turbo: false } %>

<!-- Tam sayfa yenilemesini zorla -->
<%= link_to "Admin Paneli", admin_path, data: { turbo_action: "replace" } %>

Turbo Frames: Kapsamlı Sayfa Güncellemeleri

Turbo Frames, sayfa bölümlerini bağımsız olarak güncellenebilir alanlara ayırır. Bir frame, içeriği benzersiz bir tanımlayıcıyla sarar ve bu frame içindeki herhangi bir navigasyon yalnızca sarılmış içeriği günceller.

erb
<!-- app/views/comments/index.html.erb -->
<%= turbo_frame_tag "comments" do %>
  <% @comments.each do |comment| %>
    <%= render comment %>
  <% end %>
  
  <%= link_to "Daha fazla yükle", comments_path(page: @page + 1) %>
<% end %>

Sunucu yanıtı eşleşen bir frame etiketi içermelidir. Turbo, frame içeriğini çıkarır ve DOM'daki mevcut frame'in yerini alır:

erb
<!-- app/views/comments/index.html.erb (sayfalanmış yanıt) -->
<%= turbo_frame_tag "comments" do %>
  <% @comments.each do |comment| %>
    <%= render comment %>
  <% end %>
  
  <% if @comments.any? %>
    <%= link_to "Daha fazla yükle", comments_path(page: @page + 1) %>
  <% end %>
<% end %>

Lazy loading frame'ler, içerik yüklemeyi frame viewport'a girene kadar erteler:

erb
<%= turbo_frame_tag "user_stats", src: user_stats_path(@user), loading: :lazy do %>
  <div class="animate-pulse bg-gray-200 h-24"></div>
<% end %>

Turbo Streams: Gerçek Zamanlı DOM Manipülasyonu

Turbo Streams, DOM manipülasyonu için yedi eylem sağlar: append, prepend, replace, update, remove, before ve after. Her eylem, bir elementi ID ile hedefler ve belirtilen değişikliği uygular.

erb
<!-- app/views/comments/create.turbo_stream.erb -->
<%= turbo_stream.prepend "comments" do %>
  <%= render @comment %>
<% end %>

<%= turbo_stream.update "comment_count" do %>
  <%= @comments_count %> yorum
<% end %>

<%= turbo_stream.replace "new_comment_form" do %>
  <%= render "form", comment: Comment.new %>
<% end %>

Controller'lar HTML'in yanı sıra Turbo Stream isteklerine de yanıt verir:

ruby
# app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    @comment = @post.comments.build(comment_params)
    
    respond_to do |format|
      if @comment.save
        format.turbo_stream
        format.html { redirect_to @post, notice: "Yorum eklendi" }
      else
        format.turbo_stream do
          render turbo_stream: turbo_stream.replace(
            "new_comment_form",
            partial: "form",
            locals: { comment: @comment }
          )
        end
        format.html { render :new, status: :unprocessable_entity }
      end
    end
  end
end

Ruby on Rails mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Turbo 8 Morphing: Akıllı DOM Güncellemeleri

Turbo 8, idiomorph kütüphanesi tarafından desteklenen morphing özelliğini tanıttı. Tüm sayfa bölümlerini değiştirmek yerine, morphing mevcut DOM'u gelen HTML ile karşılaştırır ve minimum değişiklikleri uygular. Bu, form durumunu, scroll pozisyonunu ve focus'u korur.

ruby
# app/models/message.rb
class Message < ApplicationRecord
  belongs_to :conversation
  
  broadcasts_refreshes
end

broadcasts_refreshes callback'i, kayıtlar değiştiğinde bir arka plan işi planlar. İş, Action Cable üzerinden tüm abone istemcilere bir yenileme sinyali yayınlar. İstemciler mevcut sayfa HTML'ini alır ve DOM'larını eşleşecek şekilde morph eder.

erb
<!-- app/views/conversations/show.html.erb -->
<%= turbo_stream_from @conversation %>

<div id="messages">
  <%= render @conversation.messages %>
</div>

<%= render "messages/form", conversation: @conversation %>

turbo_stream_from helper'ı sayfayı bir Turbo Streams kanalına abone eder. Konuşmadaki herhangi bir mesaj değiştiğinde, tüm görüntüleyenler güncellemeleri anında görür.

Morphing Yapılandırma Seçenekleri

Morphing davranışı üzerinde hassas kontrol data attribute'ları kullanır:

erb
<!-- Morph'lar boyunca elementi koru -->
<div data-turbo-permanent id="video-player">
  <video src="<%= @video.url %>" autoplay></video>
</div>

<!-- Morphing'i atla, her zaman değiştir -->
<div data-turbo-method="replace" id="chart-container">
  <%= render "chart", data: @analytics %>
</div>

Yenileme debouncer'ı aşırı yayınları önler. Birden fazla veritabanı güncellemesi hızlıca gerçekleştiğinde, yalnızca bir yenileme 500ms gecikmeden sonra tetiklenir. Bu, model başına yapılandırılabilir:

ruby
# app/models/task.rb
class Task < ApplicationRecord
  broadcasts_refreshes debounce: 1.second
end

Mülakat Soruları: Hotwire Temelleri

Teknik mülakatlar, kavramsal ve uygulama soruları aracılığıyla Hotwire bilgisini sıklıkla değerlendirir.

S: Turbo Drive, geleneksel AJAX navigasyon kütüphanelerinden nasıl farklıdır?

Turbo Drive, açık yapılandırma olmadan tüm navigasyonu otomatik olarak yakalar. Tarayıcının geri/ileri düğme davranışını korur, pushState aracılığıyla URL'yi günceller ve yönlendirmeleri şeffaf bir şekilde işler. Temel fark, aşamalı geliştirmedir: uygulamalar JavaScript olmadan çalışır ve JavaScript yüklendiğinde hız iyileştirmeleri kazanır.

S: Turbo Frames ne zaman Turbo Streams'e tercih edilmelidir?

Turbo Frames, bir linke tıklamanın belirli bir sayfa bölgesini güncellemesi gereken navigasyon tabanlı etkileşimler için uygundur. Frame'ler URL semantiğini korur ve tarayıcı geçmişiyle çalışır. Turbo Streams, birden fazla elementin aynı anda güncellenmesinin gerektiği veya güncellemelerin kullanıcı navigasyonu yerine arka plan süreçlerinden kaynaklandığı broadcast senaryolarını işler.

S: Turbo 8'deki morphing yenileme döngüsünü açıklayın.

broadcasts_refreshes tetiklendiğinde, Rails Turbo::Streams::BroadcastStreamJob'ı kuyruğa alır. İş, modelden türetilen stream adına bir yenileme eylemi yayınlar. Abone istemciler eylemi alır, mevcut sayfayı GET isteğiyle alır ve her iki DOM'u idiomorph'a iletir. Kütüphane minimum farkı hesaplar ve data-turbo-permanent ile işaretlenmiş elementleri koruyarak değişiklikleri uygular.

Gerçek Zamanlı Bildirim Sistemi Oluşturma

Pratik bir implementasyon, Hotwire'ın real-time özellikler için yeteneklerini gösterir:

ruby
# app/models/notification.rb
class Notification < ApplicationRecord
  belongs_to :user
  
  after_create_commit :broadcast_to_user
  
  private
  
  def broadcast_to_user
    broadcast_prepend_to(
      "notifications_#{user_id}",
      target: "notifications",
      partial: "notifications/notification",
      locals: { notification: self }
    )
    
    broadcast_update_to(
      "notifications_#{user_id}",
      target: "unread_count",
      html: user.notifications.unread.count.to_s
    )
  end
end

View, kullanıcıya özel kanala abone olur:

erb
<!-- app/views/layouts/_navbar.html.erb -->
<nav>
  <%= turbo_stream_from "notifications_#{current_user.id}" %>
  
  <div class="relative">
    <button>Bildirimler</button>
    <span id="unread_count" class="badge">
      <%= current_user.notifications.unread.count %>
    </span>
    
    <div id="notifications" class="dropdown">
      <%= render current_user.notifications.recent %>
    </div>
  </div>
</nav>

Sistemde herhangi bir yerde bir bildirim oluşturulduğunda, kullanıcının navbar'ı polling olmadan anında güncellenir.

Performans Optimizasyon Kalıpları

Production uygulamaları, Rails 8 production rehberinde belgelenen birkaç optimizasyon tekniğinden yararlanır.

Stream Aboneliklerini Eager Loading

Listelerde N+1 abonelik kalıplarından kaçının:

ruby
# app/controllers/projects_controller.rb
def index
  @projects = current_user.projects.includes(:tasks)
end
erb
<!-- Görev başına değil, proje başına bir kez abone ol -->
<% @projects.each do |project| %>
  <%= turbo_stream_from project %>
  <%= render project %>
<% end %>

Seçici Broadcasting

Broadcast'leri ilgili değişikliklerle sınırlayın:

ruby
# app/models/post.rb
class Post < ApplicationRecord
  broadcasts_refreshes_to ->(post) { post.published? ? :published_posts : :draft_posts }
end

Morphing ile Caching

Fragment caching, cache key'leri timestamp'ler içerdiğinde morphing ile birlikte çalışır:

erb
<% cache [@conversation, @conversation.messages.maximum(:updated_at)] do %>
  <%= render @conversation.messages %>
<% end %>

Yaygın Tuzaklar ve Çözümler

Hotwire uygulamaları implementasyonunda sıklıkla karşılaşılan birkaç sorun vardır.

JavaScript Başlatma: Stimulus controller'ları morphing'i hesaba katmalıdır. connect() ve disconnect() callback'lerini doğru kullanın ve morphing'in geçersiz kılacağı state'i saklamaktan kaçının.

app/javascript/controllers/chart_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    this.chart = new Chart(this.element, this.chartConfig)
  }
  
  disconnect() {
    this.chart?.destroy()
  }
  
  get chartConfig() {
    return JSON.parse(this.element.dataset.chartConfig)
  }
}

Form State Koruma: Morphing varsayılan olarak form girişlerini korur. Gönderimden sonra sıfırlanması gereken formlar için, Turbo Stream yanıtında açıkça temizleyin:

erb
<%= turbo_stream.replace "message_form" do %>
  <%= render "form", message: Message.new %>
<% end %>

Scroll Pozisyonu Atlamaları: scroll: :preserve seçeneği yardımcı olur, ancak karmaşık layout'lar açık scroll sabitleme gerektirebilir:

erb
<div data-turbo-scroll="preserve" id="message_list">
  <%= render @messages %>
</div>

Gelişmiş Etkileşim için Stimulus Entegrasyonu

Turbo çoğu etkileşimi işlerken, Stimulus istemci tarafı mantık gerektiren boşlukları doldurur. Kombinasyon, JavaScript'i odaklı ve minimal tutar.

app/javascript/controllers/auto_submit_controller.jsjavascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["form"]
  
  submit() {
    clearTimeout(this.timeout)
    this.timeout = setTimeout(() => {
      this.formTarget.requestSubmit()
    }, 300)
  }
}
erb
<div data-controller="auto-submit">
  <%= form_with model: @search, data: { auto_submit_target: "form" } do |f| %>
    <%= f.text_field :query, 
        data: { action: "input->auto-submit#submit" },
        placeholder: "Ara..." %>
  <% end %>
</div>

Daha gelişmiş kalıplar için caching stratejileri ve Rails test yaklaşımları modüllerini inceleyin.

Sonuç

  • Turbo Drive, linkleri ve formları yakalayarak yapılandırma gerektirmeden SPA benzeri navigasyon sağlar
  • Turbo Frames, güncellemeleri sayfa bölgeleriyle sınırlar, inline düzenleme ve lazy loading'i mümkün kılar
  • Turbo Streams, yedi eylem aracılığıyla DOM değişikliklerini yayınlar: append, prepend, replace, update, remove, before, after
  • broadcasts_refreshes ile Turbo 8 morphing, minimum DOM değişiklikleri için idiomorph kullanarak gerçek zamanlı güncellemeler sağlar
  • Morph'lar boyunca elementleri data-turbo-permanent ile koruyun
  • Broadcasting için model callback'leriyle eşleştirilmiş view'larda turbo_stream_from kullanın
  • Varsayılan 500ms debounce, hızlı güncellemeler sırasında aşırı yayınları önler
  • Stimulus controller'ları, morphing uyumluluğu için uygun connect/disconnect yaşam döngüsü yöntemlerini kullanmalıdır
  • Fragment caching, cache key'leri timestamp'ler içerdiğinde etkili kalır

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Paylaş

İlgili makaleler