ทำไมต้องใช้ Rails Action Cable?
Modern web apps ต้องการ push updates ไป client real-time: chat messages, live notifications, collaborative apps, live tickers
Action Cable = built-in WebSocket library ของ Rails เปิด two-way persistent communication ระหว่าง server และ client Server ส่งข้อมูลไป browser ได้โดยไม่ต้องรอ request (no user-prompted refresh)
Action Cable บูรณาการ WebSockets เข้า Rails app ทำให้ real-time features ที่ยากใน server-rendered apps กลายเป็นได้ง่าย
Client side: Rails ให้ JavaScript consumer subscribe channels และรับ broadcasts Developer: define backend channels (คล้าย controllers แต่สำหรับ real-time streams)
Solid Cable คืออะไร?
Action Cable เก่าๆ production ต้องใช้ Redis (หรือ PostgreSQL NOTIFY) สำหรับ broadcast messages ข้าม server processes Pub/sub service (Redis) รับผิดชอบส่ง message จาก process หนึ่งไปทุก process เพื่อ forward ให้ WebSocket clients
Solid Cable (Rails 8) = database-backed adapter แทน Redis ใช้ existing database เป็น backend เหมือน Solid Queue (Active Job) และ Solid Cache (Active Cache)
WebSocket message เข้า -> เขียนลง database table -> ทุก Action Cable instances poll table นั้นหา messages ใหม่ broadcast ให้ clients (default: ทุก 100ms) ใกล้ real-time Messages เก็บไว้แค่ระยะสั้น (24 hours default) แล้ว prune -> debug ได้ ไม่วิตกพื้นที่ database
Solid Cable = ส่วนสุดท้ายของ "Solid Trifecta": caching, background jobs, real-time messaging ทั้งหมดผ่าน database
สร้าง Rails 8 app กับ Solid Cable
สร้าง example app
rails _8.1.0_ new solid_cable_chat --database=sqlite3
cd solid_cable_chat
Rails 8 มี Solid Cable built-in ไม่ต้อง add gems
Configure Solid Cable
bin/rails solid_cable:install
Generator สร้าง config/cable.yml (set Solid Cable adapter) และ db/cable_schema.rb (schema สำหรับ messages table)
Setup Database สำหรับ Solid Cable
Default: ใช้ separate database สำหรับ Solid Cable แยกจาก app data Development: ใช้ same DB หรือ separate DB ได้ นี่ใช้ separate SQLite database
Edit config/database.yml เพิ่ม cable database ใน development:
development:
primary: <<: *default
database: storage/development.sqlite3
cable: <<: *default
database: storage/development_cable.sqlite3
migrations_paths: db/cable_migrate
Edit config/cable.yml ใช้ solid_cable adapter ใน development:
development:
adapter: solid_cable
connects_to:
database:
writing: cable
polling_interval: 0.1.seconds
message_retention: 1.day
รัน rails db:prepare
Setup Action Cable Channel
Channels = Ruby classes handle data streams (คล้าย controllers สำหรับ HTTP)
rails generate channel UserChat
Edit app/channels/user_chat_channel.rb:
class UserChatChannel < ApplicationCable::Channel
def subscribed
stream_from "user_chat_channel"
end
def unsubscribed; end
def talk(data)
message = data["content"]
ActionCable.server.broadcast("user_chat_channel", { content: message })
end
end
subscribed: stream_from "user_chat_channel" ทุกคน subscribed channel นี้จะได้รับ broadcasts
talk: custom action เรียกจาก client ด้วย perform("talk", { content: "..." }) broadcast ไปทุก subscriber
Build Consumer ใน Client
Edit app/javascript/channels/user_chat_channel.js:
import consumer from "channels/consumer";
const userChatChannel = consumer.subscriptions.create("UserChatChannel", {
connected() { console.log("Connected"); },
disconnected() { console.log("Disconnected"); },
received(data) {
const messagesDiv = document.getElementById("messages");
if (messagesDiv && data.content) {
const messageElement = document.createElement("p");
messageElement.textContent = data.content;
messagesDiv.appendChild(messageElement);
}
}
});
function sendMessage(content) {
userChatChannel.perform("talk", { content: content });
}
export { sendMessage };
window.sendMessage = sendMessage;
received(data) callback สำคัญ - เรียกเมื่อได้ broadcast จาก server update chat log real-time
Build Simple UI
rails generate controller UserChat index
View: form ส่งข้อความ + div แสดง messages
root "user_chat#index"
ทดสอบ Real-time
bin/dev -> localhost:3000 เปิด 2 tabs ส่งข้อความจาก tab หนึ่ง -> ปรากฏในอีก tab ทันที
Deploy Rails Action Cable Production
Solid Cable ใช้ database table Rails 8 default SQLite สำหรับ Solid Cable ใน new apps แต่ point ไป database ไหนก็ได้โดยเพิ่ม cable section ใน database.yml
แนะนำ: ใช้ separate database สำหรับ Solid Cable ใน production แยก real-time messaging load จาก app data หลัก (เช่น app_production_cable แยกจาก app_production)
จำ: run rails db:prepare หรือ rails db:migrate ใน production สร้าง messages table
แต่ละ WebSocket connection ใช้ server memory ต้องมี resources พอ
Configure Polling Intervals
Polling frequency configurable: ลด interval = poll บ่อยขึ้น = latency ต่ำ แต่ SELECT queries มากขึ้น เพิ่ม interval = database load น้อย แต่ delay มากขึ้น Default 0.1s (10 polls/sec) = จุดเริ่มต้นดี
Solid Cable: ปilarenสำคัญของ Solid Trifecta
Solid Cache (caching without Redis) + Solid Queue (background jobs without Redis) + Solid Cable (WebSockets without Redis) = ระบบ interactive apps ครบครัน infrastructure น้อยที่สุด
ข้อได้เปรียบ: ใช้งานได้ทันที deployment 簡單 (ไม่ต้อง Redis) performance พอสำหรับหลาย apps
Monitor production ด้วย Honeybadger สำหรับ error และ performance monitoring