บทนำ
ถ้าคุณเคยอยากให้แอป Rails ของคุณรู้สึกมีชีวิตชีวา คุณควรลองดู Action Cable มันคือวิธีที่ Rails มีให้ในการใช้ WebSockets ซึ่งหมายความว่าตอนนี้เซิร์ฟเวอร์และเบราว์เซอร์สามารถเชื่อมต่อและสนทนาแบบเรียลไทม์ได้ ไม่ต้องรีเฟรชหน้า ไม่ต้องใช้การ polling ที่ยุ่งยาก — การอัปเดตจะแสดงขึ้นทันที
ในคู่มือนี้ เราจะสร้างเดโมสนุกๆ: ตัวนับการเข้าชมแบบสด เมื่อมีใครเข้ามาที่เว็บไซต์ของคุณ เราจะบันทึกการเข้าชมนั้นในฐานข้อมูล เพิ่มค่าตัวนับในหน่วยความจำ และกระจายหมายเลขที่อัปเดตไปยังทุกคนที่ออนไลน์ ปิดแท็บ? จำนวนผู้ใช้ที่ออนไลน์จะลดลงทันที มันง่าย แต่แสดงให้เห็นถึงเวทมนตร์แบบเรียลไทม์ที่ Action Cable นำมาสู่ Rails 7
ขั้นตอนที่ 1: โมเดลการเข้าชม
เริ่มต้นกันเลย มาสร้างโมเดลเพื่อบันทึกการเข้าชมกัน
bin/rails g model Visit session_id:string ip:string user_agent:string
bin/rails db:migrate
# app/models/visit.rb
class Visit < ApplicationRecord
end
ขั้นตอนที่ 2: สร้างการเชื่อมต่อแบบกำหนดเอง
Rails มีคลาสพื้นฐานสองตัวใน app/channels/application_cable/:
- channel.rb → คลาสพื้นฐานสำหรับช่องทั้งหมดของคุณ.
- connection.rb → คลาสพื้นฐานสำหรับการเชื่อมต่อ WebSocket ทั้งหมดของคุณ.
เรามักจะไม่แก้ไขสิ่งเหล่านี้ แต่เราจะขยายมันโดยการสร้างคลาสการเชื่อมต่อของเราเองภายใน app/channels/ ซึ่งจะทำให้ค่าตั้งต้นสะอาดและทำให้ตรรกะของเราอยู่ในที่ชัดเจน
# app/channels/traffic_connection.rb
module ApplicationCable
class TrafficConnection < Connection
identified_by :session_id, :ip, :user_agent
def connect
self.session_id = request.session.id
self.ip = request.ip
self.user_agent = request.user_agent
end
end
end
ขั้นตอนที่ 3: ตัวนับในหน่วยความจำ
เราจะใช้ตัวนับแบบ atomic เพื่อให้ทุกอย่างรวดเร็ว ในการบูต เราจะดึงจำนวนการเข้าชมทั้งหมดจากฐานข้อมูล และเริ่มต้นผู้ใช้ที่ออนไลน์ที่ศูนย์
# config/initializers/traffic_counter.rb
$online_users = Concurrent::AtomicFixnum.new(0)
$total_visits = Concurrent::AtomicFixnum.new(Visit.count)
ขั้นตอนที่ 4: ช่อง
นี่คือที่ที่สนุกเกิดขึ้น — บันทึกการเข้าชม อัปเดตตัวนับ และกระจายข้อมูล
# app/channels/traffic_channel.rb
class TrafficChannel < ApplicationCable::Channel
def subscribed
# log visit
Visit.create!(session_id: connection.session_id,
ip: connection.ip,
user_agent: connection.user_agent)
# update counters
$online_users.increment
$total_visits.increment
stream_from "traffic_channel"
broadcast_counts
end
def unsubscribed
$online_users.decrement
broadcast_counts
end
private
def broadcast_counts
ActionCable.server.broadcast("traffic_channel", {
online: $online_users.value,
total: $total_visits.value
})
end
end
ขั้นตอนที่ 5: ด้าน JavaScript
เมื่อคุณรัน bin/rails generate channel Traffic Rails จะสร้างไฟล์สองไฟล์: ช่อง Ruby และไฟล์การสมัครสมาชิก JavaScript โดยค่าเริ่มต้น ไฟล์ JS จะนำเข้า consumer.js ซึ่ง Rails ก็ได้ตั้งค่าไว้ให้คุณเมื่อแอปถูกสร้างขึ้น
// app/javascript/channels/traffic_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("TrafficChannel", {
received(data) {
document.querySelector("#online-count").textContent = data.online
document.querySelector("#total-count").textContent = data.total
}
})
ไฟล์ consumer.js ถูกสร้างโดย Rails เมื่อคุณสร้างแอปใหม่ มันตั้งค่าการเชื่อมต่อ WebSocket ทั่วไปไปยัง /cable และมีลักษณะดังนี้:
// app/javascript/channels/consumer.js
import { createConsumer } from "@rails/actioncable"
export default createConsumer()
ขั้นตอนที่ 6: มุมมอง
<h1>🚦 การจราจรสด</h1>
<p>ขณะนี้ออนไลน์: <span id="online-count">0</span></p>
<p>การเข้าชมทั้งหมด: <span id="total-count"><%= Visit.count %></span></p>
ขั้นตอนที่ 7: เส้นทาง
# config/routes.rb
Rails.application.routes.draw do
root "home#index"
mount ActionCable.server => "/cable"
end
ขั้นตอนที่ 8: ลองทำดู
รันแอปของคุณด้วย bin/dev เปิดเว็บไซต์ของคุณในหลายแท็บ จำนวนผู้ใช้ที่ออนไลน์จะเพิ่มขึ้นตามแต่ละแท็บ และจะลดลงเมื่อคุณปิดแท็บ จำนวนการเข้าชมทั้งหมดจะเพิ่มขึ้นเรื่อยๆ มันน่าพอใจมากที่ได้เห็น!
หมายเหตุสำหรับการผลิต
- มีหลายพนักงาน Puma? ใช้ Redis สำหรับตัวนับ — หน่วยความจำจะไม่ซิงค์ระหว่างกระบวนการ.
- ต้องการติดตามผู้ใช้จริงแทนเซสชัน? เพิ่ม current_user ในการเชื่อมต่อ.
- การเก็บการเข้าชมในฐานข้อมูลหมายความว่าคุณสามารถทำการวิเคราะห์ในภายหลังได้ เช่น การจราจรประจำวันหรือการแบ่งเบราว์เซอร์
และนั่นคือทั้งหมด — ตัวนับการเข้าชมแบบสดใน Rails 7 ด้วย Action Cable ในไม่ถึง 100 บรรทัดของโค้ด คุณได้อัปเดตทันทีและได้ลิ้มลองสิ่งที่ WebSockets สามารถทำได้ การตั้งค่านี้ทำงานได้กับการแจ้งเตือน แดชบอร์ด และฟีเจอร์แบบเรียลไทม์ทุกประเภท เมื่อคุณได้ลองแล้ว คุณจะอยากใช้มันในทุกที่!