Rails Action Cable 和 Turbolinks:避免多重绑定
Rails Action Cable and Turbolinks: avoid multiple bindings
我的 application.html.haml 中有一个代码,它决定是否让用户订阅给定频道,具体取决于某些用户属性。
问题是,鉴于我在正文中有这段代码,当我单击 link 重定向到另一个页面时,它会再次订阅用户而不是保持旧连接,所以我有多次执行 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()
assets/javascripts/notifications/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
第一次加载页面时,当我向该频道广播一条消息时,控制台只记录一次 "Data Received"。
我单击 link 被重定向到另一个页面,我向该频道广播了一条新消息,现在控制台正在记录 "Data Received" 两次。到目前为止……
事实上,当我 运行 在 chrome 的控制台上时:
App.cable.subscriptions.subscriptions
它 returns 多个订阅到同一个频道(每次我点击 link 并被重定向到不同的页面时)。
注意:还有更多动作电缆设置我没有添加到此 post 因为它工作正常。
我怎样才能避免这种情况?有什么想法吗?
写在头部而不是 body 怎么样?
也许该事件已被 turbolinks 多次注册。
%html
%head
-# other stuff
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
- if current_user.is_admin?
:coffee
MyApp.AdminNotifications.init()
%body
-# other stuff
看起来您只需要 MyApp.AdminNotifications
的单个实例,因此您可能只需要添加一个 class 属性来标记 class 已初始化:
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#issue-125970208)。我猜您使用了内联脚本,因此您可以有条件地 运行 它 (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
)
希望对您有所帮助!
我的 application.html.haml 中有一个代码,它决定是否让用户订阅给定频道,具体取决于某些用户属性。
问题是,鉴于我在正文中有这段代码,当我单击 link 重定向到另一个页面时,它会再次订阅用户而不是保持旧连接,所以我有多次执行 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()
assets/javascripts/notifications/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
第一次加载页面时,当我向该频道广播一条消息时,控制台只记录一次 "Data Received"。 我单击 link 被重定向到另一个页面,我向该频道广播了一条新消息,现在控制台正在记录 "Data Received" 两次。到目前为止……
事实上,当我 运行 在 chrome 的控制台上时:
App.cable.subscriptions.subscriptions
它 returns 多个订阅到同一个频道(每次我点击 link 并被重定向到不同的页面时)。
注意:还有更多动作电缆设置我没有添加到此 post 因为它工作正常。
我怎样才能避免这种情况?有什么想法吗?
写在头部而不是 body 怎么样? 也许该事件已被 turbolinks 多次注册。
%html
%head
-# other stuff
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
- if current_user.is_admin?
:coffee
MyApp.AdminNotifications.init()
%body
-# other stuff
看起来您只需要 MyApp.AdminNotifications
的单个实例,因此您可能只需要添加一个 class 属性来标记 class 已初始化:
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#issue-125970208)。我猜您使用了内联脚本,因此您可以有条件地 运行 它 (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
)
希望对您有所帮助!