Как установить параметры при подписке на канал 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 ответа

Решение

Несколько вещей, чтобы подумать здесь:

  1. Порядок, в котором все скрипты загружаются.
  2. Конкретное время "создания экземпляров" переменных ruby ​​(где / когда они могут быть доступны).
  3. Понимая, что простой старый 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'

Что происходит:

  1. Когда страница загружается, представление добавляет атрибут данных data-visit-id в начало страницы.
  2. Канал visit.coffee читает этот атрибут из заголовка страницы.
  3. затем 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)
Другие вопросы по тегам