บทนำ

ถ้าคุณเคยอยากให้แอป 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 สามารถทำได้ การตั้งค่านี้ทำงานได้กับการแจ้งเตือน แดชบอร์ด และฟีเจอร์แบบเรียลไทม์ทุกประเภท เมื่อคุณได้ลองแล้ว คุณจะอยากใช้มันในทุกที่!