Rails Action Cable и Turbolinks: избегайте множественных привязок
У меня есть код в моем application.html.haml, который решает, подписывать ли пользователя на данный канал или нет, в зависимости от некоторого атрибута пользователя.
Дело в том, что, учитывая, что у меня есть этот фрагмент кода в теле, когда я нажимаю ссылку, чтобы перенаправить ее на другую страницу, он снова подписывает пользователя вместо сохранения старого соединения, поэтому у меня есть receive()
метод выполняется несколько раз.
Это мой код в application.html.haml
:
%html
%head
-# other stuff
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
%body
-# other stuff
- if current_user.is_admin?
:coffee
MyApp.AdminNotifications.init()
активы / JavaScripts/ уведомление /admin_notifications.js.coffee
window.MyApp.AdminNotifications = class AdminNotifications
@init: ->
App.cable.subscriptions.create "ProductsChannel",
received: (data) ->
console.log 'Data Received' # This is being executed multiple times
При первой загрузке страницы, когда я транслирую сообщение на этот канал, консоль записывает "Полученные данные" только один раз. Я щелкаю ссылку, чтобы перенаправить ее на другую страницу, я транслирую новое сообщение на этот канал, и теперь консоль дважды регистрирует "Получено данных". И так до сих пор...
На самом деле, когда я бегу на консоли Chrome:
App.cable.subscriptions.subscriptions
Он возвращает несколько подписок на один и тот же канал (один раз за каждый раз, когда я нажимал на ссылку и перенаправлялся на другую страницу).
Примечание. В этом посте я не добавляю больше действий по настройке кабеля, потому что он работает нормально.
Как я могу избежать этого? Есть идеи?
2 ответа
Похоже, вы хотите только один экземпляр MyApp.AdminNotifications
так что вам может понадобиться только добавить атрибут класса, чтобы указать, что класс был инициализирован:
window.MyApp.AdminNotifications = class AdminNotifications
@init: ->
unless @initialized
App.cable.subscriptions.create "ProductsChannel",
received: (data) ->
console.log 'Data Received'
@initialized = true
В будущем вы можете захотеть обернуть Action Cable API для управления своими собственными подписками.
Как правило, при работе с Turbolinks предпочтительно включать как можно больше материала в файл application.js, а не во встроенные скрипты (см. https://github.com/rails/rails/pull/23012). Я предполагаю, что вы использовали встроенный скрипт, чтобы вы могли его условно запустить (if current_user.is_admin?
). Популярный подход заключается в использовании метатегов для передачи этих данных, поэтому в вашей голове:
<meta name="current-user-is-admin" content="true">
Тогда вы могли бы иметь:
window.MyApp.User = class User
constructor: ->
@isAdmin = @getMeta('current-user-is-admin') == 'true'
getMeta: (name) ->
meta = document.querySelector("meta[name=#{name}]")
meta.getAttribute('content') if meta
И наконец, чтобы удалить AdminNotifications
Код инициализации из макета включите его где-нибудь в ваш application.js:
document.addEventListener('turbolinks:load', ->
window.MyApp.currentUser = new window.MyApp.User
window.MyApp.AdminNotifications.init() if window.MyApp.currentUser.isAdmin
)
Надеюсь, это поможет!
Как насчет записи в голове вместо тела? Возможно, событие было зарегистрировано несколько раз через турболинк.
%html
%head
-# other stuff
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
- if current_user.is_admin?
:coffee
MyApp.AdminNotifications.init()
%body
-# other stuff