1 Kas yra Action Cable?
Action Cable be jokių problemų integruoja WebSocketus su jūsų „Rails“ programa. Tai leidžia rašyti realaus laiko funkcijas „Ruby“ kalba taip pat, kaip ir visą kitą „Rails“ programą, išlaikant efektyvumą ir skalėjimą. Tai yra visiškai integruota paslauga, kuri teikia tiek kliento pusės „JavaScript“ karkasą, tiek serverio pusės „Ruby“ karkasą. Jūs turite prieigą prie viso savo domeno modelio, kuris yra parašytas naudojant „Active Record“ arba jūsų pasirinktą ORM.
2 Terminologija
Action Cable naudoja WebSocketus vietoj HTTP užklausos-atsakymo protokolo. Tie patys Action Cable ir WebSocketai įveda keletą mažiau žinomų terminų:
2.1 Ryšiai
Ryšiai sudaro pagrindą kliento-serverio santykiams. Vienas Action Cable serveris gali tvarkyti kelis ryšio pavyzdžius. Jis turi vieną ryšio pavyzdį vienam WebSocket ryšiui. Vienas vartotojas gali turėti kelis atvirus WebSocketus jūsų programoje, jei jie naudoja kelias naršyklės korteles ar įrenginius.
2.2 Vartotojai
WebSocket ryšio klientas vadinamas vartotoju. Action Cable vartotojas yra sukurtas kliento pusės „JavaScript“ karkaso.
2.3 Kanalai
Kiekvienas vartotojas gali prenumeruoti kelis kanalus. Kiekvienas kanalas apima loginį darbo vienetą, panašų į tai, ką daro valdiklis tipinėje MVC struktūroje. Pavyzdžiui, galite turėti „ChatChannel“ ir „AppearancesChannel“, o vartotojas gali būti prenumeruotas vienam ar abiem šiems kanalams. Bent jau vartotojas turėtų būti prenumeruotas vienam kanalui.
2.4 Prenumeratoriai
Kai vartotojas yra prenumeruotas kanalui, jis veikia kaip prenumeratorius. Ryšys tarp prenumeratoriaus ir kanalo yra, kaip ir galima manyti, vadinamas prenumerata. Vartotojas gali veikti kaip prenumeratorius tam tikram kanalui bet kiek kartų. Pavyzdžiui, vartotojas gali prenumeruoti kelias pokalbių kambarius tuo pačiu metu. (Ir prisiminkite, kad fizinis vartotojas gali turėti kelis vartotojus, vieną kiekvienai atvirei kortelei / įrenginiui, kuris yra atviresnis jūsų ryšiui).
2.5 Pub/Sub
Pub/Sub arba leidimas-prenumeravimas nurodo žinučių eilės paradigmą, kurioje informacijos siuntėjai (leidėjai) siunčia duomenis abstrakčiai gavėjų kategorijai (prenumeratoriams), nenurodydami individualių gavėjų. Action Cable naudoja šį požiūrį bendrauti tarp serverio ir daugybės klientų.
2.6 Transliacijos
Transliacija yra leidimo-prenumeravimo nuoroda, kuria bet kas, siunčiantis transliuotojo, tiesiogiai siunčia kanalo prenumeratoriams, kurie stebi tą pavadinimą. Kiekvienas kanalas gali stebėti nulį ar daugiau transliacijų.
3 Serverio pusės komponentai
3.1 Ryšiai
Kiekvienam WebSocketui, priimtam serverio, sukuriamas ryšio objektas. Šis objektas tampa visų kanalų prenumeratų tėvu, kurie yra sukurti nuo to momento. Ryšis pats nesiduria su jokia specifine programos logika, išskyrus autentifikaciją ir autorizaciją. WebSocket ryšio klientas vadinamas ryšio vartotoju. Vienas vartotojas sukurs vieną vartotojo-ryšio porą vienam naršyklės skirtuke, langelyje ar įrenginyje, kurį jie turi atvirą.
Ryšiai yra ApplicationCable::Connection
pavyzdžiai, kurie išplečia ActionCable::Connection::Base
. ApplicationCable::Connection
klasėje jūs patvirtinate įeinantį ryšį ir, jei vartotojas gali būti nustatytas, tęsite su jo nustatymu.
3.1.1 Ryšio nustatymas
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
private
def find_verified_user
if verified_user = User.find_by(id: cookies.encrypted[:user_id])
verified_user
else
reject_unauthorized_connection
end
end
end
end
Čia identified_by
nurodo ryšio identifikatorių, kuris vėliau gali būti naudojamas rasti konkretų ryšį. Atkreipkite dėmesį, kad bet kas, pažymėta kaip identifikatorius, automatiškai sukurs delegatą su tuo pačiu pavadinimu visiems kanalų pavyzdžiams, sukurtiems iš ryšio.
Šis pavyzdys remiasi tuo, kad jūs jau esate apdorotas vartotojo autentifikacijos kažkur kitur savo programoje ir sėkminga autentifikacija nustato užšifruotą slapuką su vartotojo ID.
Slapukas automatiškai siunčiamas ryšio pavyzdžiui, kai bandote sukurti naują ryšį, ir jį naudojate, kad nustatytumėte current_user
. Nurodydami ryšį šiuo pačiu dabartiniu vartotoju, taip pat užtikrinate, kad vėliau galėsite gauti visus atvirus ryšius pagal tam tikrą vartotoją (ir galbūt juos visus atjungti, jei vartotojas yra ištrintas arba neturi teisės).
Jei jūsų autentifikavimo metodas apima sesijos naudojimą, naudojate slapukų saugyklą sesijai, jūsų sesijos slapukas yra pavadinimu _session
, o naudotojo ID raktas yra user_id
, galite naudoti šį metodą:
verified_user = User.find_by(id: cookies.encrypted['_session']['user_id'])
3.1.2 Išimčių tvarkymas
Pagal nutylėjimą, neapdorotos išimtys yra sugaunamos ir įrašomos į „Rails“ žurnalo failą. Jei norite visuotinai perimti šias išimtis ir pranešti apie jas išoriniam klaidų sekimo paslaugai, pavyzdžiui, galite tai padaryti naudodami rescue_from
:
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
rescue_from StandardError, with: :report_error
private
def report_error(e)
SomeExternalBugtrackingService.notify(e)
end
end
end
3.1.3 Ryšio atgalinimo iškvietimai
Yra before_command
, after_command
ir around_command
atgalinimo iškvietimai, kurie gali būti iškviesti prieš, po arba aplink kiekvieną kliento gautą komandą atitinkamai.
Čia terminas „komanda“ nurodo bet kokį kliento gautą sąveiką (prenumeravimą, atsisakymą prenumeruoti arba veiksmų vykdymą):
# app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :user
around_command :set_current_account
private
def set_current_account(&block)
# Dabar visi kanalai gali naudoti Current.account
Current.set(account: user.account, &block)
end
end
end
3.2 Kanalai
Kanalas apgaubia loginį darbą, panašų į tai, ką daro valdiklis tipinėje MVC konfigūracijoje. Pagal nutylėjimą „Rails“ sukuria pagrindinę ApplicationCable::Channel
klasę
(kuri išplečia ActionCable::Channel::Base
) bendrai logikai tarp jūsų kanalų apgaubti.
3.2.1 Pagrindinio kanalo konfigūracija
# app/channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
Tada galėtumėte sukurti savo kanalų klases. Pavyzdžiui, galite turėti
ChatChannel
ir AppearanceChannel
:
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
end
# app/channels/appearance_channel.rb
class AppearanceChannel < ApplicationCable::Channel
end
Vartotojas tada gali būti prenumeruotas vienam ar abiem šiems kanalams.
3.2.2 Prenumeratos
Vartotojai prenumeruoja kanalus, veikdami kaip prenumeratoriai. Jų ryšys yra vadinamas prenumerata. Gauti pranešimai tada yra nukreipiami į šių kanalų prenumeratas pagal kanalo prenumeratoriaus siunčiamą identifikatorių.
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
# Iškviečiama, kai vartotojas sėkmingai
# tampa šio kanalo prenumeratoriumi.
def subscribed
end
end
3.2.3 Išimčių tvarkymas
Kaip ir su ApplicationCable::Connection
, taip pat galite naudoti rescue_from
konkrečiame kanale, kad tvarkytumėte iškeltus išimtis:
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
rescue_from 'MyError', with: :deliver_error_message
private
def deliver_error_message(e)
broadcast_to(...)
end
end
3.2.4 Kanalo atgalinimo iškvietimai
ApplicationCable::Channel
teikia keletą atgalinimo iškvietimų, kurie gali būti naudojami, kad būtų galima paleisti logiką
kanalo gyvavimo ciklo metu. Galimi atgalinimo iškvietimai yra:
before_subscribe
after_subscribe
(taip pat pavadinimu:on_subscribe
)before_unsubscribe
after_unsubscribe
(taip pat pavadinimu:on_unsubscribe
)
PASTABA: after_subscribe
atgalinimo iškvietimas yra paleidžiamas, kai tik yra iškviesta subscribed
metodas,
net jei prenumerata buvo atmesta naudojant reject
metodą. Norėdami paleisti after_subscribe
tik sėkmingoms prenumeratoms, naudokite after_subscribe :send_welcome_message, unless: :subscription_rejected?
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
after_subscribe :send_welcome_message, unless: :subscription_rejected?
after_subscribe :track_subscription
private
def send_welcome_message
broadcast_to(...)
end
def track_subscription
# ...
end
end
4 Kliento komponentai
4.1 Ryšiai
Vartotojai savo pusėje reikalauja ryšio egzemplioriaus. Tai gali būti nustatoma naudojant šį numatytąjį „JavaScript“, kurį generuoja „Rails“:
4.1.1 Prijungti prenumeratorių
// app/javascript/channels/consumer.js
// „Action Cable“ teikia pagrindą dirbti su „WebSockets“ „Rails“.
// Galite generuoti naujus kanalus, kuriuose gyvena „WebSocket“ funkcijos, naudodami komandą `bin/rails generate channel`.
import { createConsumer } from "@rails/actioncable"
export default createConsumer()
Tai paruoš šaltinį, kuris pagal nutylėjimą prisijungs prie /cable
jūsų serverio.
Ryšys nebus nustatytas, kol nebus nurodyta bent viena prenumerata,
kurią norite turėti.
Prenumeratorius galima pasirinktinai perduoti argumentą, kuriame nurodomas URL, prie kurio prisijungti. Tai gali būti eilutė arba funkcija, kuri grąžina eilutę, kuri bus iškviesta, kai WebSocket bus atidarytas.
// Nurodyti kitą prisijungimo URL
createConsumer('wss://example.com/cable')
// Arba naudojant WebSocketus per HTTP
createConsumer('https://ws.example.com/cable')
// Naudoti funkciją, kuri dinamiškai generuoja URL
createConsumer(getWebSocketURL)
function getWebSocketURL() {
const token = localStorage.get('auth-token')
return `wss://example.com/cable?token=${token}`
}
4.1.2 Prenumeratorius
Vartotojas tampa prenumeratoriumi, sukurdamas prenumeratą tam tikram kanalui:
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"
consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" })
// app/javascript/channels/appearance_channel.js
import consumer from "./consumer"
consumer.subscriptions.create({ channel: "AppearanceChannel" })
Nors tai sukuria prenumeratą, funkcionalumas, reikalingas atsakyti į gautus duomenis, bus aprašytas vėliau. Vartotojas gali veikti kaip prenumeratorius tam tikram kanalui bet kiek kartų. Pavyzdžiui, vartotojas gali prenumeruoti kelias pokalbių kambarius tuo pačiu metu:
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"
consumer.subscriptions.create({ channel: "ChatChannel", room: "1-as kambarys" })
consumer.subscriptions.create({ channel: "ChatChannel", room: "2-as kambarys" })
5 Kliento-serverio sąveikos
5.1 Srautai
Srautai suteikia mechanizmą, pagal kurį kanalai maršrutizuoja paskelbtą turinį (transliacijas) savo prenumeratoriams. Pavyzdžiui, šis kodas naudoja stream_from
prenumeruoti transliaciją pavadinimu chat_Geriausias kambarys
, kai :room
parametras yra "Geriausias kambarys"
:
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat_#{params[:room]}"
end
end
Tada, kitur jūsų „Rails“ aplikacijoje, galite transliuoti į tokią patalpą, iškviesdami broadcast
:
ActionCable.server.broadcast("chat_Geriausias kambarys", { body: "Šis kambarys yra geriausias." })
Jei turite srautą, susijusį su modeliu, tada transliavimo pavadinimą galima generuoti iš kanalo ir modelio. Pavyzdžiui, šis kodas naudoja stream_for
prenumeruoti transliaciją kaip posts:Z2lkOi8vVGVzdEFwcC9Qb3N0LzE
, kur Z2lkOi8vVGVzdEFwcC9Qb3N0LzE
yra „Post“ modelio GlobalID.
class PostsChannel < ApplicationCable::Channel
def subscribed
post = Post.find(params[:id])
stream_for post
end
end
Tada galite transliuoti į šį kanalą, iškviesdami broadcast_to
:
PostsChannel.broadcast_to(@post, @comment)
5.2 Transliacijos
Transliacija yra pub/sub nuoroda, kuriai transliuojantys duomenys tiesiogiai nukreipiami į kanalo prenumeratorius, kurie transliuoja tą pavadinimą. Kiekvienas kanalas gali transliuoti nulinį arba daugiau transliacijų.
Transliacijos yra tik internetinė eilė ir priklauso nuo laiko. Jei vartotojas nesistebi (prenumeruoja tam tikrą kanalą), jis negaus transliacijos, jei vėliau prisijungs.
5.3 Prenumeratos
Kai vartotojas prenumeruoja kanalą, jis veikia kaip prenumeratorius. Ši ryšys vadinamas prenumerata. Įeinančios žinutės tada nukreipiamos į šiuos kanalo prenumeratas pagal kabelio vartotojo siunčiamą identifikatorių.
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"
consumer.subscriptions.create({ channel: "ChatChannel", room: "Geriausias kambarys" }, {
received(data) {
this.appendLine(data)
},
appendLine(data) {
const html = this.createLine(data)
const element = document.querySelector("[data-chat-room='Geriausias kambarys']")
element.insertAdjacentHTML("beforeend", html)
},
createLine(data) {
return `
<article class="chat-line">
<span class="speaker">${data["sent_by"]}</span>
<span class="body">${data["body"]}</span>
</article>
`
}
})
5.4 Parametrų perdavimas kanalams
Galite perduoti parametrus iš kliento pusės į serverio pusę, kuriant prenumeratą. Pavyzdžiui:
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat_#{params[:room]}"
end
end
Objektas, perduotas kaip pirmasis argumentas subscriptions.create
, tampa parametrų maišu kabelio kanale. Reikalingas raktažodis channel
:
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"
consumer.subscriptions.create({ channel: "ChatChannel", room: "Geriausias kambarys" }, {
received(data) {
this.appendLine(data)
},
appendLine(data) {
const html = this.createLine(data)
const element = document.querySelector("[data-chat-room='Geriausias kambarys']")
element.insertAdjacentHTML("beforeend", html)
},
createLine(data) {
return `
<article class="chat-line">
<span class="speaker">${data["sent_by"]}</span>
<span class="body">${data["body"]}</span>
</article>
`
}
})
# Irgkur jūsų programoje tai yra iškviesta, galbūt
# iš „NewCommentJob“.
ActionCable.server.broadcast(
"chat_#{room}",
{
sent_by: 'Paul',
body: 'Tai yra nuostabi pokalbių programa.'
}
)
5.5 Pranešimo persiuntimas
Daugelio klientų išsiųsto pranešimo persiuntimas bet kuriems kitoms prisijungusioms klientams yra įprasta naudojimo atvejis.
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat_#{params[:room]}"
end
def receive(data)
ActionCable.server.broadcast("chat_#{params[:room]}", data)
end
end
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"
const chatChannel = consumer.subscriptions.create({ channel: "ChatChannel", room: "Geriausias kambarys" }, {
received(data) {
// data => { sent_by: "Paul", body: "Tai yra nuostabi pokalbių programa." }
}
}
chatChannel.send({ sent_by: "Paul", body: "Tai yra nuostabi pokalbių programa." })
Persiųstas pranešimas bus gautas visų prisijungusių klientų, įskaitant klientą, kuris išsiuntė pranešimą. Atkreipkite dėmesį, kad parametrai yra tokie patys, kaip ir prenumeruojant kanalą.
6 Pilno naudojimo pavyzdžiai
Šie sąrankos žingsniai yra bendri abiem pavyzdžiams:
6.1 Pavyzdys 1: Vartotojų pasirodymai
Štai paprastas kanalo pavyzdys, kuris stebi, ar vartotojas yra prisijungęs ar ne, ir kuriame puslapyje jie yra. (Tai naudinga, jei norite sukurti funkcijas, kurios rodo žalią tašką šalia vartotojo vardo, jei jie yra prisijungę).
Sukurkite serverio pusės pasirodymo kanalą:
# app/channels/appearance_channel.rb
class AppearanceChannel < ApplicationCable::Channel
def subscribed
current_user.appear
end
def unsubscribed
current_user.disappear
end
def appear(data)
current_user.appear(on: data['appearing_on'])
end
def away
current_user.away
end
end
Kai užsakymas yra pradėtas, subscribed
atgalinis iškvietimas yra paleidžiamas, ir mes pasinaudojame šia galimybe pasakyti "dabartinis vartotojas tikrai pasirodė". Ši pasirodymo / dingimo API gali būti paremta Redis, duomenų baze ar bet kuo kitu.
Sukurkite klientinį pasirodymo kanalo užsakymą:
// app/javascript/channels/appearance_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("AppearanceChannel", {
// Iškviečiama tik kartą, kai užsakymas yra sukurtas.
initialized() {
this.update = this.update.bind(this)
},
// Iškviečiama, kai užsakymas yra pasiruošęs naudoti serveryje.
connected() {
this.install()
this.update()
},
// Iškviečiama, kai WebSocket ryšys yra uždarytas.
disconnected() {
this.uninstall()
},
// Iškviečiama, kai užsakymas yra atmestas serverio.
rejected() {
this.uninstall()
},
update() {
this.documentIsActive ? this.appear() : this.away()
},
appear() {
// Iškviečia `AppearanceChannel#appear(data)` serveryje.
this.perform("appear", { appearing_on: this.appearingOn })
},
away() {
// Iškviečia `AppearanceChannel#away` serveryje.
this.perform("away")
},
install() {
window.addEventListener("focus", this.update)
window.addEventListener("blur", this.update)
document.addEventListener("turbo:load", this.update)
document.addEventListener("visibilitychange", this.update)
},
uninstall() {
window.removeEventListener("focus", this.update)
window.removeEventListener("blur", this.update)
document.removeEventListener("turbo:load", this.update)
document.removeEventListener("visibilitychange", this.update)
},
get documentIsActive() {
return document.visibilityState === "visible" && document.hasFocus()
},
get appearingOn() {
const element = document.querySelector("[data-appearing-on]")
return element ? element.getAttribute("data-appearing-on") : null
}
})
6.1.1 Kliento-Serverio sąveika
Klientas prisijungia prie Serverio per
createConsumer()
. (consumer.js
). Serveris identifikuoja šį ryšį pagalcurrent_user
.Klientas užsiregistruoja pasirodymo kanalui per
consumer.subscriptions.create({ channel: "AppearanceChannel" })
. (appearance_channel.js
)Serveris atpažįsta, kad buvo pradėtas naujas užsakymas pasirodymo kanalui ir paleidžia savo
subscribed
atgalinį iškvietimą, iškviečiantappear
metodącurrent_user
. (appearance_channel.rb
)Klientas atpažįsta, kad užsakymas buvo įtvirtintas ir iškviečia
connected
(appearance_channel.js
), kuris savo ruožtu iškviečiainstall
irappear
.appear
iškviečiaAppearanceChannel#appear(data)
serveryje ir pateikia duomenų maišą{ appearing_on: this.appearingOn }
. Tai įmanoma, nes serverio pusės kanalo egzempliorius automatiškai atskleidžia visus viešus metodus, deklaruotus klasėje (minus atgaliniai iškvietimai), kad šie būtų pasiekiami kaip nuotoliniai procedūrų kvietimai per užsakymoperform
metodą.Serveris gauna užklausą dėl
appear
veiksmo pasirodymo kanale, skirtącurrent_user
identifikuotam ryšiui (appearance_channel.rb
). Serveris gauna duomenis su:appearing_on
raktu iš duomenų maišo ir nustato jį kaip reikšmę:on
rakčiai, kuri perduodamacurrent_user.appear
.
6.2 Pavyzdys 2: Naujų internetinių pranešimų gavimas
Pasirodymo pavyzdys buvo visiškai apie serverio funkcionalumo atskleidimą klientinio kvietimo per WebSocket ryšį. Bet puikus dalykas apie WebSocket yra tai, kad tai yra dvipusis kelias. Taigi, dabar parodykime pavyzdį, kai serveris iškviečia veiksmą kliente.
Tai yra internetinių pranešimų kanalas, kuris leidžia jums paleisti klientinio pusės internetinius pranešimus, kai jūs transliuojate atitinkamoms srautams:
Sukurkite serverio internetinių pranešimų kanalą:
# app/channels/web_notifications_channel.rb
class WebNotificationsChannel < ApplicationCable::Channel
def subscribed
stream_for current_user
end
end
Sukurkite klientinio pusės internetinių pranešimų kanalo užsakymą:
// app/javascript/channels/web_notifications_channel.js
// Klientinė pusė, kuri priima, kad jau prašėte
// teisės siųsti internetinius pranešimus.
import consumer from "./consumer"
consumer.subscriptions.create("WebNotificationsChannel", {
received(data) {
new Notification(data["title"], { body: data["body"] })
}
})
Transliuokite turinį į internetinių pranešimų kanalo egzempliorių iš kitos vietos jūsų programoje:
# Kažkur jūsų programoje tai yra iškviesta, galbūt iš NewCommentJob
WebNotificationsChannel.broadcast_to(
current_user,
title: 'Nauji dalykai!',
body: 'Visos naujienos tinkamos spausdinimui'
)
WebNotificationsChannel.broadcast_to
kvietimas deda žinutę į dabartinio užsakymo adapterio pubsub eilės po atskiru transliavimo vardu kiekvienam vartotojui. Vartotojui su ID 1, transliavimo vardas būtų web_notifications:1
.
Kanalas buvo nurodytas transliuoti viską, kas atvyksta į web_notifications:1
tiesiai į klientą, iškviečiant received
atgalinį iškvietimą. Duomenys, perduodami kaip argumentas, yra maišas, išsiųstas kaip antrasis parametras į serverio pusės transliavimo iškvietimą, JSON koduotas kelionės metu per laidą ir išpakuotas kaip duomenų argumentas, atvykstantis kaip received
.
6.3 Išsamūs pavyzdžiai
Norėdami pamatyti, kaip nustatyti Action Cable savo „Rails“ programoje ir pridėti kanalus, žr. rails/actioncable-examples saugyklą.
7 Konfigūracija
Action Cable turi dvi privalomas konfigūracijas: užsakymo adapterį ir leidžiamus užklausos kilmės adresus.
7.1 Užsakymo adapteris
Pagal numatytuosius nustatymus, Action Cable ieško konfigūracijos failo config/cable.yml
.
Failas turi nurodyti adapterį kiekvienam „Rails“ aplinkai. Daugiau informacijos apie adapterius žr.
S priklausomybėmis skyrių.
development:
adapter: async
test:
adapter: test
production:
adapter: redis
url: redis://10.10.3.153:6381
channel_prefix: appname_production
7.1.1 Adapterio konfigūracija
Žemiau pateikiamas prenumeratos adapterių sąrašas, skirtas galutiniams vartotojams.
7.1.1.1 Async Adapteris
Async adapteris skirtas plėtrai/testavimui ir neturėtų būti naudojamas gamyboje.
7.1.1.2 Redis Adapteris
Redis adapteriui reikia, kad vartotojai pateiktų URL, rodantį į Redis serverį.
Be to, gali būti pateiktas channel_prefix
, kad būtų išvengta kanalo pavadinimų susidūrimo
naudojant tą patį Redis serverį keliose programose. Daugiau informacijos rasite Redis Pub/Sub dokumentacijoje.
Redis adapteris taip pat palaiko SSL/TLS ryšius. Reikalingi SSL/TLS parametrai gali būti perduodami konfigūracijos YAML failo ssl_params
raktui.
production:
adapter: redis
url: rediss://10.10.3.153:tls_port
channel_prefix: appname_production
ssl_params: {
ca_file: "/path/to/ca.crt"
}
ssl_params
parametrams perduodami tiesiogiai į OpenSSL::SSL::SSLContext#set_params
metodą ir gali būti bet koks SSL konteksto galiojantis atributas.
Daugiau informacijos rasite OpenSSL::SSL::SSLContext dokumentacijoje apie kitus galimus atributus.
Jei naudojate savo parengtus sertifikatus "redis adapter" už ugniasienės ir norite praleisti sertifikato tikrinimą, tada ssl verify_mode
turėtų būti nustatytas kaip OpenSSL::SSL::VERIFY_NONE
.
ĮSPĖJIMAS: Nerekomenduojama naudoti VERIFY_NONE
gamyboje, nebent visiškai suprantate saugumo padarinius. Norėdami nustatyti šią parinktį "Redis adapteriui", konfigūracija turėtų būti ssl_params: { verify_mode: <%= OpenSSL::SSL::VERIFY_NONE %> }
.
7.1.1.3 PostgreSQL Adapteris
PostgreSQL adapteris naudoja Active Record prisijungimo keitiklį ir todėl
programos config/database.yml
duomenų bazės konfigūraciją, kaip savo prisijungimą.
Tai gali pasikeisti ateityje. #27214
7.2 Leidžiami užklausos kilmės
Action Cable priima užklausas tik iš nurodytų kilmės vietų, kurios yra perduodamos kaip masyvas į serverio konfigūraciją. Kilmės vietos gali būti eilučių ar reguliarių išraiškų pavyzdžiai, prieš kuriuos bus tikrinama atitikties sąlyga.
config.action_cable.allowed_request_origins = ['https://rubyonrails.com', %r{http://ruby.*}]
Norėdami išjungti ir leisti užklausas iš bet kurios kilmės:
config.action_cable.disable_request_forgery_protection = true
Pagal numatytuosius nustatymus, Action Cable leidžia visus užklausas iš localhost:3000, kai vyksta plėtros aplinkoje.
7.3 Vartotojo konfigūracija
Norėdami konfigūruoti URL, į savo HTML išdėstymo HEAD pridėkite action_cable_meta_tag
iškvietimą.
Tai naudoja URL arba kelią, kuris paprastai nustatomas per config.action_cable.url
aplinkos konfigūracijos failuose.
7.4 Darbinio baseino konfigūracija
Darbinis baseinas naudojamas vykdyti prisijungimo atgalinių iškvietimų ir kanalo veiksmų atitvėrimą nuo serverio pagrindinės gijos. Action Cable leidžia programai konfigūruoti vienu metu vykdomų gijų skaičių darbinėje baseine.
config.action_cable.worker_pool_size = 4
Taip pat atkreipkite dėmesį, kad jūsų serveris turi pateikti bent tiek pat duomenų bazės
prisijungimų, kiek turite darbuotojų. Numatytasis darbinio baseino dydis yra 4, todėl
tai reiškia, kad turite pateikti bent 4 duomenų bazės prisijungimus.
Tai galite pakeisti config/database.yml
per pool
atributą.
7.5 Kliento pusės žurnalavimas
Kliento pusės žurnalavimas numatytasis išjungtas. Galite tai įjungti nustatydami ActionCable.logger.enabled
reikšmę į true
.
import * as ActionCable from '@rails/actioncable'
ActionCable.logger.enabled = true
7.6 Kitos konfigūracijos
Kitas bendras pasirinkimas, kurį galima konfigūruoti, yra žurnalo žymės, taikomos kaskartinei prisijungimo žurnalo įrašiklio. Štai pavyzdys, naudojantis vartotojo paskyros ID, jei jis yra prieinamas, kitu atveju "no-account" žymėjimui:
config.action_cable.log_tags = [
-> request { request.env['user_account_id'] || "no-account" },
:action_cable,
-> request { request.uuid }
]
Visų konfigūracijos parinkčių sąrašui žiūrėkite
ActionCable::Server::Configuration
klasės dokumentacijoje.
8 Paleidimas kaip atskiri kabelio serveriai
Action Cable gali veikti kaip jūsų "Rails" programos dalis arba kaip atskiras serveris. Plėtros metu veikimas kaip jūsų "Rails" programos dalis paprastai yra gerai, tačiau gamyboje jį turėtumėte paleisti kaip atskirą serverį.
8.1 Programoje
Action Cable gali veikti kartu su jūsų "Rails" programa. Pavyzdžiui, norint
klausyti WebSocket užklausų adresu /websocket
, nurodykite tą kelią
config.action_cable.mount_path
:
# config/application.rb
class Application < Rails::Application
config.action_cable.mount_path = '/websocket'
end
Jei iškviečiama action_cable_meta_tag
, galima naudoti ActionCable.createConsumer()
prisijungti prie kabelio
serverio. Kitu atveju, pirmasis argumentas createConsumer
yra nurodytas kelias (pvz., ActionCable.createConsumer("/websocket")
).
Kiekvienai jūsų sukurtai serverio instancijai ir kiekvienam darbuotojui, kurį jūsų serveris sukuria, taip pat turėsite naują Action Cable instanciją, tačiau "Redis" arba "PostgreSQL" adapteris sinchronizuoja žinutes tarp prisijungimų.
8.2 Atskirai
Kabelio serveriai gali būti atskirti nuo jūsų įprasto programos serverio. Tai vis tiek yra "Rack" programa, bet tai yra savarankiška "Rack" programa. Rekomenduojamas pagrindinis nustatymas yra šis: ```ruby
cable/config.ru
require_relative "../config/environment" Rails.application.eager_load!
run ActionCable.server ```
Tada, norint paleisti serverį:
bundle exec puma -p 28080 cable/config.ru
Tai paleidžia kabelio serverį 28080 prievade. Norėdami pranešti „Rails“, kad naudotų šį serverį, atnaujinkite savo konfigūraciją:
# config/environments/development.rb
Rails.application.configure do
config.action_cable.mount_path = nil
config.action_cable.url = "ws://localhost:28080" # naudokite wss:// produkcijoje
end
Galų gale, įsitikinkite, kad teisingai sukonfigūravote vartotoją.
8.3 Pastabos
WebSocket serveris neturi prieigos prie sesijos, tačiau jis turi prieigą prie slapukų. Tai gali būti naudojama, kai reikia tvarkyti autentifikaciją. Galite pamatyti vieną būdą tai padaryti su „Devise“ šiame straipsnyje.
9 Priklausomybės
„Action Cable“ teikia prenumeratos adapterio sąsają, skirtą apdoroti savo
pubsub vidinius. Pagal numatytuosius nustatymus yra įtraukti asinchroniniai, tiesioginiai, „PostgreSQL“ ir „Redis“
adapteriai. Naujose „Rails“ programose numatytasis adapteris
yra asinchroninis (async
) adapteris.
Ruby pusės dalykas yra sukurtas viršuje websocket-driver, nio4r ir concurrent-ruby.
10 Diegimas
„Action Cable“ veikia naudojant „WebSocket“ ir gijas. Abi pagrindinės struktūros ir vartotojo nurodytos kanalo darbo yra apdorojamos viduje naudojant „Ruby“ natyvų gijų palaikymą. Tai reiškia, kad galite naudoti visus savo esamus „Rails“ modelius be jokių problemų, jei nesukėlėte jokių gijų saugumo klaidų.
„Action Cable“ serveris įgyvendina „Rack“ lizdų užgrobimo API, tai leidžia naudoti daugiausiai gijų pagrįstą modelį valdyti ryšius viduje, nepriklausomai nuo to, ar taikomosios programos serveris turi daugiau nei vieną giją ar ne.
Atitinkamai, „Action Cable“ veikia su populiariais serveriais, tokiais kaip „Unicorn“, „Puma“ ir „Passenger“.
11 Testavimas
Detalią informaciją apie tai, kaip testuoti „Action Cable“ funkcionalumą, rasite testavimo vadove.
Atsiliepimai
Jūs esate skatinami padėti pagerinti šio vadovo kokybę.
Prašome prisidėti, jei pastebite rašybos klaidų ar faktinių klaidų. Norėdami pradėti, galite perskaityti mūsų dokumentacijos prisidėjimo skyrių.
Taip pat gali būti nepilnos informacijos arba informacijos, kuri nėra atnaujinta. Prašome pridėti bet kokią trūkstamą dokumentaciją pagrindiniam. Patikrinkite Edge vadovus pirmiausia, ar problemas jau išspręsta arba ne pagrindinėje šakoje. Patikrinkite Ruby on Rails vadovų gaires dėl stiliaus ir konvencijų.
Jei dėl kokios nors priežasties pastebite kažką, ką reikia ištaisyti, bet negalite patys tai pataisyti, prašome pranešti apie problemą.
Ir galiausiai, bet ne mažiau svarbu, bet koks diskusijos dėl Ruby on Rails dokumentacijos yra labai laukiamos oficialiame Ruby on Rails forume.