Как установить параметры при подписке на канал Action Cable
Я пытался разобраться с боевиком в течение нескольких месяцев. Пожалуйста помоги.
У меня есть "Соединение" - я не могу установить identified_by :current_user
потому что эта конечная точка также должна использоваться внешним API, который использует WebSockets. Невозможно использовать куки-файлы браузера для аутентификации конечной точки API.
Файлы и поддержка
Подключение:/app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
Источник:/app/channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
У меня есть конкретный канал посещений:/app/channels/visits_channel.rb
class VisitChannel < ApplicationCable::Channel
def subscribed
stream_from "visit_#{params[:visit_id]}"
end
end
Тогда у меня есть мой канал coffeescript:/app/assets/javascripts/channels/visit.coffee
App.visit = App.cable.subscriptions.create { channel: 'VisitChannel', visit_id: '42' },
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
console.log data
push: ->
@perform 'push'
Тогда у меня есть ответный звонок на мою модель посещения:/app/models/visit.rb
class Visit < ApplicationRecord
after_save :push_to_action_cable
**** detail of model removed ****
def push_to_action_cable
ActionCable.server.broadcast("visit_#{self.id}", self)
end
end
Это работает отлично, он выводит на консоль объект каждый раз, и только этот объект с идентификатором 42
Вот мой вопрос:
В канале coffeescript: найден на /app/assets/javascripts/channels/visit.coffee
- Как мне установить visit_id
чтобы я мог "слушать" изменения только в том посещении, которое хочу?
App.visit = App.cable.subscriptions.create { channel: 'VisitChannel', visit_id: 'HOW_DO_I_SET_THIS?' },
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
console.log data
push: ->
@perform 'push'
Что я пробовал:
Я пробовал каждый вариант таких вещей, как:
App.visit = App.cable.subscriptions.create { channel: 'VisitChannel', visit_id: <%= @visit.id %> }
результаты в:
ExecJS::RuntimeError in Visits#action_cable
Showing /Users/johnsalzarulo/code/uvohealth/app/views/layouts/application.html.erb where line #9 raised:
SyntaxError: [stdin]:1:81: unexpected <
а также
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: "#{ params[:id] }")
результаты в:
ExecJS::RuntimeError in Visits#action_cable
Showing /Users/johnsalzarulo/code/uvohealth/app/views/layouts/application.html.erb where line #9 raised:
SyntaxError: [stdin]:1:93: unexpected :
а также
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: "#{ @visit.id }")
результаты в:
visit.self-e04de4513d06884493c48f4065f94d23255be682f915e26766c54bb9d17ef305.js?body=1:4 Uncaught TypeError: Cannot read property 'id' of undefined
at visit.self-e04de4513d06884493c48f4065f94d23255be682f915e26766c54bb9d17ef305.js?body=1:4
at visit.self-e04de4513d06884493c48f4065f94d23255be682f915e26766c54bb9d17ef305.js?body=1:18
(anonymous) @ visit.self-e04de4513d06884493c48f4065f94d23255be682f915e26766c54bb9d17ef305.js?body=1:4
(anonymous) @ visit.self-e04de4513d06884493c48f4065f94d23255be682f915e26766c54bb9d17ef305.js?body=1:18
а также
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: "#{ visit.id }")
результаты в:
visit.self-b636f38376edc085c15c2cfc4d524bafc5c5163a8c136b80ba1dda12813fc0b5.js?body=1:4 Uncaught ReferenceError: visit is not defined
at visit.self-b636f38376edc085c15c2cfc4d524bafc5c5163a8c136b80ba1dda12813fc0b5.js?body=1:4
at visit.self-b636f38376edc085c15c2cfc4d524bafc5c5163a8c136b80ba1dda12813fc0b5.js?body=1:18
(anonymous) @ visit.self-b636f38376edc085c15c2cfc4d524bafc5c5163a8c136b80ba1dda12813fc0b5.js?body=1:4
(anonymous) @ visit.self-b636f38376edc085c15c2cfc4d524bafc5c5163a8c136b80ba1dda12813fc0b5.js?body=1:18
В заключение
Я перепробовал еще много комбинаций. Единственное, что ВИД работ бросал <script>
в шаблон представления для той страницы, которая явно подписалась на посещение, но тогда я не получил выгоды от обратных вызовов, плюс я знаю, что это не "путь рельсов".
Это были часы чтения этих документов и попыток сделать эту работу. Кто-нибудь может пролить некоторый свет на то, что мне здесь не хватает?
2 ответа
Несколько вещей, чтобы подумать здесь:
- Порядок, в котором все скрипты загружаются.
- Конкретное время "создания экземпляров" переменных ruby (где / когда они могут быть доступны).
- Понимая, что простой старый JavaScript может быть использован в глупом CoffeeScript.
Тем не менее, вот решение, которое сработало для меня:
Файлы и поддержка
Все файлы, используемые в вопросе, заданном выше, остаются без изменений, за исключением того, что ниже. Чтобы это работало, вам нужно сослаться на файлы выше и файлы ниже для полного стека.
Основной шаблон для моего приложения: app/views/layouts/application.html.erb
Обратите внимание на строку внутри тега head yield(:head_attributes)
<!DOCTYPE html>
<html>
<head <%= yield(:head_attributes) %> >
<title>Uvo Health</title>
<%= action_cable_meta_tag %>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body <%= yield(:body_attributes) %> >
<%= render 'layouts/navbar' unless @hide_nav %>
<%= render 'shared/flash_messages' %>
<%= yield %>
<%= yield :page_js %>
</body>
</html>
Представление для страницы, на которой я пытаюсь использовать actioncable. В моем случае это: app/views/visits/action_cable.html.erb
- В большинстве случаев это, вероятно, будет вашим show.html.erb
или же index.html.erb
Обратите внимание на content_for
<%= content_for(:head_attributes) do %>data-visit-id="<%= @visit.id %>"<% end %>
<div class='container'>
<%= render 'visits/visit_overview' %>
</div>
Тогда в моем канале посещения /app/assets/javascripts/channels/visit.coffee
App.visit = App.cable.subscriptions.create { channel: 'VisitChannel', visit_id: document.querySelector('head').dataset.visitId },
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
console.log data
push: ->
@perform 'push'
Что происходит:
- Когда страница загружается, представление добавляет атрибут данных
data-visit-id
в начало страницы. - Канал
visit.coffee
читает этот атрибут из заголовка страницы. - затем
visit.coffee
можете использовать эту переменную для подписки на соответствующий канал.
Другие решения не сработали, потому что я пытался получить доступ к вещам в неправильном "порядке", то есть загрузить переменную до ее создания. Надеюсь, что это полезно для других. Этот поставил меня в тупик на целых 5 часов.
Установить visit_id
в теге HTML, может быть, в body
тег в вашем файле макета.
<body data-visit-id="<%= @visit.id %>">
Теперь прочитайте это из JS так:
document.querySelector('body').dataset.visitId
Ваша строка создания подписки будет выглядеть так:
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: document.querySelector('body').dataset.visitId)