如何在订阅Action Cable频道

时间:2017-08-31 00:10:15

标签: ruby-on-rails coffeescript ruby-on-rails-5 channel actioncable

我一直试图让我的头脑绕着动作电缆看似几个月。请帮忙。

我有一个“连接” - 我无法设置identified_by :current_user,因为此端点也需要由使用WebSockets的外部API使用。无法使用浏览器cookie来验证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

这是完美的工作,它每次都会向控制台提供对象,只有ID为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

结束

我尝试过很多种组合。 KIND的唯一工作就是将<script>投入到明确订阅访问的页面的视图模板中,但后来我没有得到回调的好处,而且我知道这不是“轨道方式”。

阅读这些文档并尝试完成这项工作需要几个小时。任何人都可以了解我在这里缺少的东西吗?

2 个答案:

答案 0 :(得分:2)

在这里要考虑的一些事情:

  1. 脚本全部加载的顺序。
  2. &#34;实例化的具体时间&#34;红宝石变量,(何时/何时可以访问)。
  3. 意识到普通的&#39; JavaScript可以在愚蠢的CoffeeScript中使用。
  4. 那说 - 这是解决方案对我有用:

    文件和支持

    上面提到的问题中使用的所有文件都没有变化,除了下面的内容。为了使其正常工作,您需要引用上面的文件和下面的文件以获得完整的堆栈。

    我的应用的主要模板:app/views/layouts/application.html.erb请注意标题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.erbindex.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可以使用此变量订阅相应的频道。
    4. 其他解决方案不起作用,因为我试图以错误的顺序访问事物&#39;意思是,在变量实例化之前加载它。希望这对其他人有帮助。这个让我坚持了5个小时。

答案 1 :(得分:1)

在HTML标记中设置visit_id,也可以在布局文件的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)