4

I have a code in my application.html.haml that decides whether to subscribe the user to a given channel or not, depending on some user attribute.

The thing is that, given I have this piece of code in the body, when I click a link to be redirected to another page, it subscribes the user again instead of keeping the old connection, so I have the receive() method being executed multiple times.

This is my code in 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

The first time the page is loaded, when I broadcast a message to that channel, the console is logging "Data Received" just once. I click a link to be redirected to another page, I broadcast a new message to that channel, and now the console is logging "Data Received" twice. And so far so on...

In fact, when I run on the chrome's console:

App.cable.subscriptions.subscriptions

It returns multiple subscriptions to the same channel (once for every time I clicked on a link and got redirected to a different page).

Note: There is more action cable setup that I am not adding to this post because it's working fine.

How can I avoid that? Any ideas?

4

2 回答 2

0

看起来您只需要 的单个实例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#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
)

希望有帮助!

于 2017-05-11T23:03:19.083 回答
0

用头脑而不是身体写作怎么样?也许该事件已被 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
于 2017-05-10T16:57:35.033 回答