บทความนี้ได้รับแรงบันดาลใจบางส่วนจากบทที่จะเผยแพร่ในหนังสือ Advanced CableReady ของผู้เขียน และปรับให้เหมาะกับโพสต์แขกนี้สำหรับ AppSignal
การแจ้งเตือนเป็นเรื่องที่เกี่ยวข้องข้าม cutting concerns ทั่วไปของแอปพลิเคชันเว็บหลายตัว
Gem Noticed ทำให้การพัฒนาการแจ้งเตือนง่ายขึ้นอย่างมหัศจรรย์ โดยให้โมเดลที่ backed โดยฐานข้อมูลและ delivery methods ที่เสียบได้สำหรับแอปพลิเคชัน Ruby on Rails ของคุณ มันมาพร้อมกับการสนับสนุน built-in สำหรับ mailers, websockets และ delivery methods อื่นๆ อีกสองตัว
เราจะตรวจสอบคุณสมบัติของการใช้ gem CableReady สำหรับการทริกเกอร์การแจ้งเตือนระบบในแอปพลิเคชัน Ruby on Rails ของคุณ
ลองเริ่มกันเถอะ!
ข้อกำหนดเบื้องต้นและความต้องการ
บางครั้ง คุณอาจต้องทริกเกอร์การแจ้งเตือนระบบจากแอปของคุณ คุณสามารถบรรลุสิ่งนี้ด้วย Notifications API
ตัวอย่างเช่น สมมติว่าแอปพลิเคชันของคุณอนุญาตให้ผู้ใช้อัปโหลดไฟล์ขนาดใหญ่ซึ่งใช้เวลานานในการ transcode คุณอาจต้องการส่งการแจ้งเตือนให้ผู้ใช้เมื่ออัปโหลดวิดีโอเสร็จสิ้น นี่หมายความว่าพวกเขาสามารถเปลี่ยนไปทำงานใหม่ได้ระหว่างนั้น และไม่ต้องเก็บแอปพลิเคชันของคุณเปิดไว้เป็นนาที
โชคดีที่มันง่ายที่จะ implement และ fleshed out system notifications ด้วยข้อกำหนดเบื้องต้นสองข้อนี้:
- Noticed มีการสนับสนุน custom delivery methods (Noticed เปิด API เรียบง่ายเพื่อ implement กลไกการขนส่งใดๆ ที่คุณชอบ — ตัวอย่างเช่น โพสต์ไปยัง Discord servers)
- CableReady มี operation การแจ้งเตือนในกระทงของมัน
รายการข้อกำหนดสำหรับ CableReady และ Noticed สั้น — คุณเพียงต้องการ:
- ActionCable server ที่ทำงานอยู่
- ActiveJob backend (มักใช้โดย Noticed)
หมายเหตุ: โค้ดตัวอย่างทั้งหมดสำหรับโปรเจกต์นี้มีบน GitHub คุณสามารถติดตามได้ด้านล่าง — เราจะแนะนำทีละขั้นตอน
CableReady Primer สำหรับแอปพลิเคชัน Ruby on Rails ของคุณ
ลองเริ่มต้นด้วยการทำให้ตัวเองคุ้นเคยกับ CableReady เปิดตัวในปี 2017 สามารถคิดได้ว่าเป็น "ActionCable standard library ที่หายไป"
ก่อนมาถึงของ Turbo วิธีเดียวในการสร้างแอปพลิเคชัน real-time ใน Ruby on Rails คือผ่าน ActionCable ActionCable เป็น wrapper แบบ native ของ Rails รอบ WebSockets ให้ API ฝั่ง server และ client เพื่อส่งข้อความผ่านการเชื่อมต่อที่คงที่ในทั้งสองทิศทางตลอดเวลา
ข้อเสียของแนวทางนี้คือ (และยังคงเป็น) คุณต้องเขียน boilerplate code มากมายเพื่อทำให้มันเกิดขึ้น
นี่คือที่ที่ CableReady ช่วยโดยให้ abstraction layer รอบหลาย DOM operations ที่จะถูกทริกเกอร์บน server ตัวอย่างมีดังนี้:
- DOM mutations (
inner_html,insert_adjacent_html,morph, ฯลฯ) - DOM element property mutations (
add_css_class,remove_css_class,set_dataset_property, ฯลฯ) - dispatching arbitrary DOM events
- browser history manipulations
- notifications (ซึ่งเราจะใช้)
CableReady Server และ Client
CableReady ทำงานอย่างไร? ในข้อความสรุป มันประกอบด้วยส่วนฝั่ง server และ client
ฝั่ง server โมดูล CableReady::Broadcaster สามารถ include ในส่วนใดก็ได้ของแอปพลิเคชันที่ต้องการ 可能是在 job, model callback, หรือ controller ธรรมดา แต่ก่อนอื่น ต้องมี ActionCable channel อยู่แล้ว ตามเอกสารทางการของ CableReady:
สังเกตว่า visitors เรียกว่า stream identifier มันสามารถใช้เพื่อ target กลุ่มผู้ชมกว้างหรือเฉพาะ clients ที่ subscribe channel ของคุณ เพื่อปิดตัวอย่าง เราสามารถ include broadcaster module ในโมเดลและส่ง console.log ไปยัง client หลังสมัครสมาชิก:
ฝั่ง client logic เรียบง่าย สร้าง subscription ไปยัง channel ที่กล่าวมาข้างต้น จากนั้นใน hook received เรียก CableReady.perform บน operations ทั้งหมดที่ส่งผ่านสาย:
CableReady vs Turbo สำหรับ Rails
สรุป เมื่อไหนควรใช้ CableReady และเมื่อไหนควรหลีกเลี่ยง?
ด้วยการแนะนำ Turbo ชุมชนพัฒนาเว็บได้รับ toolbox ที่ทรงพลังสำหรับสร้างแอปพลิเคชัน reactive ที่ server-rendered โดยเป็นเทคโนโลยี frontend โดยปกติพร้อม server-side bindings ที่ทรงพลังสำหรับ Rails มันเข้ากับ stack Model-View-Controller (MVC) มาตรฐานได้ดี ดังนั้นมันสามารถครอบคลุมความต้องการส่วนใหญ่ของแอปทั่วไป
CableReady ในทางตรงข้าม เป็น Swiss army knife ของการพัฒนา real-time Rails และควรใช้ด้วยความระมัดระวัง มันเป็น abstraction ที่ทรงพลังซึ่งดูควบคุมได้ แต่หากคุณจินตนาการว่าส่วนใดของ DOM ของคุณสามารถ mutate ได้จากทุกที่ในแอป คุณจะเข้าใจว่าสิ่งนี้อาจนำไปสู่ race conditions และบั๊กที่ยากต่อการติดตาม
มีกรณีอย่างที่มีอยู่ที่นี่ ที่ CableReady ทำให้สมบูรณ์เพราะมันอนุญาตให้ควบคุม DOM ได้ละเอียดกว่า
ถามสำหรับ TLDR เรียบง่าย ฉันจะตอบว่า Turbo สำหรับนักพัฒนาแอปพลิเคชัน ในขณะที่ CableReady สำหรับผู้สร้างไลบรารี แต่เราจะเห็นว่ามีพื้นที่สีเทาระหว่างสองตัว
Noticed — การแจ้งเตือนที่เรียบง่ายสำหรับแอปพลิเคชัน Ruby on Rails
ไลบรารีที่สองที่เราจะใช้เพื่อส่งการแจ้งเตือนระบบคือ gem Noticed ของ Chris Oliver ที่หัวใจของมัน สร้างบนโมเดล ActiveRecord ที่สร้างแบบจำลอง การแจ้งเตือนเดี่ยวให้กับผู้รับ มันเก็บ metadata ทั่วไป เช่น:
- ใครที่การแจ้งเตือนถูกส่งไป (ผู้รับ)
- เมื่อใดที่การแจ้งเตือนถูกอ่าน
- พารามิเตอร์ใดๆ ที่การแจ้งเตือนเชื่อมโยงกับ (โดยทั่วไปเป็นการอ้างอิงโมเดลอื่น)
หากคุณคุ้นเคยกับวิธีการทำงานของ meta-tables ของ ActiveStorage/ActionText นี่คือสิ่งคล้ายกันมาก
ติดกับสิ่งนี้ Noticed ใช้ POROs (Plain Old Ruby Objects คือ อ็อบเจกต์โดยไม่มีการเชื่อมโยงกับ Rails หรือ frameworks อื่นๆ) ซึ่งทำหน้าที่เป็น blueprint สำหรับการแจ้งเตือนจริง เหล่านี้ ในทางที่ค่อนข้าง misleading เรียกว่า Notifications เช่นกัน และพกพา logic เกี่ยวกับวิธี render และ distribute พวกเขา นี่คือตัวอย่างจาก README:
เราจะเห็นสิ่งนี้ทำงานในไม่ช้า สิ่งที่น่าสนใจโดยเฉพาะคือการเรียก deliver_by เพราะมันกำหนดว่าการแจ้งเตือนนี้ควรใช้ delivery methods ไหน:
deliver_by :databaseจัดเก็บระคอร์ด Notification (ของโมเดลที่กล่าวมา) เพื่อเข้าถึงภายหลังdeliver_by :action_cableส่งผ่าน ActionCable channel และ stream ที่กำหนด (เริ่มต้นNoticed::NotificationChannel)deliver_by :emailระบุ mailer ที่ใช้ส่งการแจ้งเตือน ตัวอย่างแสดงวิธีคำนึงถึง preferences ที่ผู้รับอาจตั้งไว้
เป้าหมายของเราสำหรับส่วนที่เหลือของบทความคือ implement custom delivery method ที่จะส่งการแจ้งเตือนระบบของเรา
Custom Delivery Method: System Notifications ผ่าน Notifications API
ก่อนที่เราจะเริ่มทำสิ่งนี้ ให้ล้างพื้นที่โดยการสร้างแอปพลิเคชัน Rails ใหม่ เนื่องจากการรวมกับ CableReady ง่ายกว่านี้ ฉันเลือกตัวเลือก JavaScript esbuild แทน importmaps:
หมายเหตุ: ณ เวลาเขียน เวอร์ชัน Rails ปัจจุบันคือ 7.0.4 หากคุณมีแอปพลิเคชัน Rails ที่มีอยู่ คุณสามารถข้ามขั้นตอนถัดไปได้ แต่ให้แน่ใจว่าคุณมีโมเดล User หรือแนวคิดคล้ายกันเพื่อทำหน้าที่เป็น notification recipient
1. เตรียม Recipients
Noticed ต้องการโมเดล User เพื่อทำหน้าที่เป็น recipients เพื่อความกระชับ ให้ดึง Devise และ generate โมเดล User
หลังจากนั้น เปิด Rails console และสร้างผู้ใช้ตัวอย่าง:
2. เพิ่ม Noticed
ต่อไป เราจะเพิ่ม Noticed ใน bundle และ generate database model
เราทำตามที่บอก รัน db:migrate และเพิ่ม polymorphic has_many association ให้โมเดล User ของเรา:
ชิ้นส่วนสุดท้ายก่อนที่เราจะทดสอบคือการสร้าง blueprint PORO:
เรา tweak มันเล็กน้อย เพื่อให้มันใช้แค่ database delivery method และ placeholder message สำหรับตอนนี้ คุณโดยทั่วไปจะเพิ่ม required params ที่นี่ เช่น model id เพื่อสร้างข้อความและ URL ที่ลิงก์ไป — ดู README ของ Noticed สำหรับรายละเอียด
ใช้แค่ Rails console เราสามารถสาธิตวิธีส่งการแจ้งเตือนตาม PORO นี้ได้:
ตามที่เราเห็น Noticed ทำ database insert ดังนั้นตอนนี้เราสามารถดึง Notifications ทั้งหมดสำหรับผู้ใช้ที่ระบุได้:
สิ่งนี้เพียงพอสำหรับเราในการสร้าง index view เรียบง่ายที่แสดงรายการการแจ้งเตือนที่ส่งแล้วทั้งหมดสำหรับ current user:
หลังจาก spin up แอปด้วย bin/dev เราสามารถล็อกอินและไปที่ https://localhost:3000/notifications:

3. การติดตั้ง CableReady
เพื่อใช้ CableReady เราต้องติดตั้งมัน โชคดีที่ทำได้เร็ว:
ลอง generate NotificationChannel เพื่อส่งข้อความของเรา:
นี่จะเพิ่ม ActionCable (JavaScript) dependencies ที่ขาดหายไป และ scaffold ไฟล์ channel ที่เกี่ยวข้อง โดยเฉพาะ app/channels/notification_channel.rb และ app/javascript/channels/notification_channel.js
สำหรับ channel ฝั่ง server เราสืบทอดจาก Noticed::NotificationChannel:
ก่อนที่เราจะต่อไป เราต้องแน่ใจว่า ActionCable ของเราได้รับการรับรองตัวตนสำหรับผู้ใช้ Devise ฉันจะไม่ลงลึกลงในรายละเอียดที่นี่ boilerplate ที่จำเป็นดูเหมือนนี้:
ดูเอกสาร StimulusReflex สำหรับตัวเลือกอื่นๆ
ฝั่ง client เราต้องเพิ่มโค้ด setup น้อยที่กล่าวมาข้างต้น:
หมายเหตุ: Redis จำเป็นสำหรับ ActionCable ให้ทำงาน ดังนั้นส่วนที่เหลือของบทความนี้สมมติว่าคุณมี local server ทำงานอยู่
4. การ Implement Delivery Method
เพื่อ broadcast system notifications ให้ generate delivery method ใหม่:
คลาสที่ scaffold มาเป็นแบบนี้:
ลองต่อไปด้วยการวาดภาพว่าเราคาดหวังว่าเมธอด deliver จะทำงานอย่างไร
เราขอยืมเมธอด channel ส่วนหนึ่งจาก delivery method ActionCable built-in มันอนุญาตให้เราส่ง channel ผ่าน class method option ไม่เช่นนั้น fallback ไปที่ Noticed::NotificationsChannel ที่ให้มา
จากนั้นเราใช้เมธอด notification ของ CableReady เพื่อ broadcast instance ที่เกี่ยวข้องไปยัง recipient
เพื่อนำไปใช้ เราต้องเชื่อมมันกับ notification PORO ของเรา:
5. นำไปใช้งาน
ตอนนี้สิ่งที่เหลือคือลองใช้งาน เราสามารถรันนี้อีกครั้งจาก Rails console:
สมมติว่าคุณยังล็อกอินอยู่ บราวเซอร์จะขออนุญาตให้รับการแจ้งเตือนในนามของแอปก่อน:

เมื่อคุณยืนยันแล้ว คุณจะได้ pop-up notification สวยงามจากบราวเซอร์ของคุณ:

สรุป
ผ่านการทัวร์แบบเร็วกับ CableReady และ Noticed เราได้สาธิตวิธีรวม native browser API เข้าแอปของคุณ ผลลัพธ์คือวิธีที่เรียบง่าย สอดคล้องกันในการส่งการแจ้งเตือนระบบให้ผู้ใช้ของคุณ
Use case นี้ยังมีไว้สำหรับแสดงให้เห็นว่าการผสม CableReady เข้า use case ของคุณง่ายแค่ไหน หากคุณคิดล่วงหน้าหนึ่งขั้น การ decouple delivery method ที่วาดไว้เป็นไลบรารีไม่ได้ยาก
ฉันหวังว่านี้จะแรงบันดาลใจให้คุณมองหาการแสดงออกของ vertical reactive problem domains ในแอปของคุณและลอง CableReady
อ่านเพิ่มเติมโดยการซื้อหนังสือ Advanced CableReady ใหม่ของฉัน
ใช้รหัสคูปอง APPSIGNAL-PROMO และประหยัด $10!
ขอให้เขียนโค้ดสนุกสนาน!
P.S. หากคุณต้องการอ่านโพสต์ Ruby Magic ทันทีที่เผยแพร่ สมัครรับจดหมายข่าว Ruby Magic และจะไม่พลาดโพสต์ใดๆ!