Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosfreeCodeCamp.org: TimescaleDB Course – PostgreSQL for Time-Series Data(23.09.2026 um 12:30 Uhr)
Windows Tipps & SecurityAndroid 17: Rollout auf Samsung-Galaxy-Smartphones verzögert sich(23.09.2026 um 11:42 Uhr)
Unix & Linux ServerUSN-8733-2: Gzip vulnerabilities(22.09.2026 um 18:04 Uhr)
Sichere ProgrammierungHow to Build Custom PowerPoint Add-Ins for Enterprise Teams(23.09.2026 um 11:25 Uhr)
Sichere ProgrammierungSearch Google Jobs in Real-Time with Go and SerpApi 🚀(23.09.2026 um 12:13 Uhr)
Sichere ProgrammierungA Psychological State is a Coefficient Vector(23.09.2026 um 12:16 Uhr)
YouTube Security VideosfreeCodeCamp.org: TimescaleDB Course – PostgreSQL for Time-Series Data(23.09.2026 um 12:30 Uhr)
Windows Tipps & SecurityAndroid 17: Rollout auf Samsung-Galaxy-Smartphones verzögert sich(23.09.2026 um 11:42 Uhr)
Unix & Linux ServerUSN-8733-2: Gzip vulnerabilities(22.09.2026 um 18:04 Uhr)
Sichere ProgrammierungHow to Build Custom PowerPoint Add-Ins for Enterprise Teams(23.09.2026 um 11:25 Uhr)
Sichere ProgrammierungSearch Google Jobs in Real-Time with Go and SerpApi 🚀(23.09.2026 um 12:13 Uhr)
Sichere ProgrammierungA Psychological State is a Coefficient Vector(23.09.2026 um 12:16 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Rails + OpenAI API — Build a Streaming Chat Interface with Turbo

You've got Rails down. You've got Hotwire, Stimulus, and background jobs wired up. Now let's wire in actual AI. This post builds a working chat interface that streams OpenAI responses in real-time using Turbo Streams. No JavaScript…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

You've got Rails down. You've got Hotwire, Stimulus, and background jobs wired up. Now let's wire in actual AI.



This post builds a working chat interface that streams OpenAI responses in real-time using Turbo Streams. No JavaScript frameworks. No React. Just Rails doing what Rails does best.






What We're Building



A simple chat UI where users type messages and get AI responses streamed word-by-word. The kind of thing you'd see in ChatGPT, but built with Rails in under 100 lines of code.






Setup



Add the OpenAI gem:




gem 'ruby-openai'
bundle install






Set your API key:




export OPENAI_API_KEY=sk-...






Or use Rails credentials:




bin/rails credentials:edit






Add to the file:




openai:
api_key: sk-...









The Chat Model



We need to store messages. Keep it simple:




bin/rails g model Chat message:text response:text
db:migrate









The Controller



Here's where the magic happens. We're using ruby-openai with streaming enabled, and piping each chunk through Turbo Streams:




class ChatsController < ApplicationController
def create
@chat = Chat.create!(message: params[:message])

# Start streaming the response
stream_openai_response(@chat)

redirect_to chats_path
end

private

def stream_openai_response(chat)
client = OpenAI::Client.new(
access_token: Rails.application.credentials.openai[:api_key]
)

# Create a placeholder for the streaming response
chat.update(response: "")

# Stream to Turbo Frame
Turbo::StreamsChannel.broadcast_append_to(
"chat_#{chat.id}",
target: "response_#{chat.id}",
partial: "chats/response",
locals: { chat: chat, content: "" }
)

# Stream the actual response chunks
client.chat(
parameters: {
model: "gpt-4o-mini",
messages: [{ role: "user", content: chat.message }],
stream: proc do |chunk|
content = chunk.dig("choices", 0, "delta", "content")
next unless content

# Append each chunk to the response
Turbo::StreamsChannel.broadcast_append_to(
"chat_#{chat.id}",
target: "response_content_#{chat.id}",
partial: "chats/chunk",
locals: { chunk: content }
)
end
}
)
end
end









The Views



app/views/chats/index.html.erb:




<%= turbo_stream_from "chats" %>

<div id="chats">
<%= render @chats %>
</div>

<%= form_with url: chats_path, data: { turbo: true } do |f| %>
<%= f.text_field :message, placeholder: "Ask something..." %>
<%= f.submit "Send" %>
<% end %>






app/views/chats/_chat.html.erb:




<%= turbo_stream_from "chat_#{chat.id}" %>

<div class="chat-message">
<p><strong>You:</strong> <%= chat.message %></p>
<div id="response_<%= chat.id %>">
<strong>AI:</strong>
<span id="response_content_<%= chat.id %>"></span>
</div>
</div>






app/views/chats/_chunk.html.erb:




<%= chunk %>









How It Works




  1. User submits a message → create action fires

  2. We immediately broadcast a placeholder Turbo Frame

  3. OpenAI streams response chunks one at a time

  4. Each chunk gets broadcast via ActionCable to the waiting frame

  5. Words appear on the page as they're generated



The stream: proc block in the OpenAI client runs for every chunk. We're not waiting for the full response. We're pushing pixels as soon as OpenAI sends them.






Making It Production-Ready



Move to background job for long responses:




class StreamChatJob < ApplicationJob
def perform(chat_id)
chat = Chat.find(chat_id)
# ... same streaming logic
end
end






Add rate limiting to prevent abuse:




class ChatsController < ApplicationController
before_action :check_rate_limit

private

def check_rate_limit
# Simple Redis-based rate limit
key = "chat:#{request.remote_ip}"
count = Redis.current.incr(key)
Redis.current.expire(key, 1.hour) if count == 1

render json: { error: "Rate limited" }, status: 429 if count > 10
end
end






Handle errors gracefully:




begin
client.chat(parameters: { ... })
rescue OpenAI::Error => e
Turbo::StreamsChannel.broadcast_replace_to(
"chat_#{chat.id}",
target: "response_#{chat.id}",
partial: "chats/error",
locals: { error: "Something went wrong. Try again." }
)
end









Why This Pattern Works





  • No polling — WebSocket pushes from server


  • No React — Turbo handles DOM updates


  • Progressive enhancement — Works without JS, streams with it


  • Simple mental model — One controller action, one job, done






Next Up



Streaming is cool, but what if you want the AI to actually know things? In the next post, we'll add embeddings and vector search so your Rails app can answer questions about your actual data.






Part of the Ruby for AI series. Building AI-powered Rails apps, one post at a time.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Rails + OpenAI API — Build a Streaming Chat Interface with Turbo

Thematisch verwandte Begriffe: Rails, OpenAI, Build, Streaming · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96258 | A vulnerability has been found in onSite internet GmbH Auktion NG Auktio…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick