I've been trying to get my head around action cable for what seems like months. Please help.
几个月来,我一直在努力让自己的大脑专注于动作有线电视。请帮助。
I have a "Connection" - I can't set the identified_by :current_user
because this endpoint also needs to be consumed by an external API that uses WebSockets. Can't use browser cookies to authenticate the API endpoint.
我有一个“连接”——我不能设置identified_by:current_user,因为使用WebSockets的外部API也需要使用这个端点。无法使用浏览器cookie对API端点进行身份验证。
Files & Support
Connection: /app/channels/application_cable/connection.rb
连接:/ app /渠道/ application_cable / connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
Channel: /app/channels/application_cable/channel.rb
渠道:/ app /通道/ application_cable / channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
I have a specific Visits Channel: /app/channels/visits_channel.rb
我有一个特定的访问通道:/app/ Channel /visits_channel.rb
class VisitChannel < ApplicationCable::Channel
def subscribed
stream_from "visit_#{params[:visit_id]}"
end
end
Then I have my coffeescript channel: /app/assets/javascripts/channels/visit.coffee
然后我有咖啡稿频道:/app/assets/javascript /channel /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'
Then I have a callback on my visit model: /app/models/visit.rb
然后我的访问模型:/app/模型/访问。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
This is working perfectly, it puts to the console the object every time and only that object with an ID of 42
这是一个完美的工作,它每次都把对象放到控制台,只有那个ID为42的对象。
Here is my question:
Within the coffeescript channel: found at /app/assets/javascripts/channels/visit.coffee
- How do I set the visit_id
so that I can "listen" for the changes on only the visit I want?
在咖啡稿频道:在/app/资产/javascript /频道/访问。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'
What I have tried:
I have tried every variation of things like:
我尝试过各种各样的东西,比如:
App.visit = App.cable.subscriptions.create { channel: 'VisitChannel', visit_id: <%= @visit.id %> }
results in:
结果:
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 <
and
和
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: "#{ params[:id] }")
results in:
结果:
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 :
and
和
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: "#{ @visit.id }")
results in:
结果:
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
and
和
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: "#{ visit.id }")
results in:
结果:
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
In Closing
I have tried many many more combinations. The only thing that KIND of works was throwing a <script>
into the view template for that page that explicitly subscribed to the visit, but then I didn't get the benifit of the callbacks, plus I know this isn't the "rails way".
我尝试过更多的组合。这类工作的惟一功能是将
It's been hours of reading these docs and trying to make this work. Can anyone shed some light on what I'm missing here?
我花了好几个小时阅读这些文档,并试图让它发挥作用。有人能解释一下我在这里错过了什么吗?
2 个解决方案
#1
1
Set the visit_id
in a HTML tag, maybe in the body
tag in your layout file.
在HTML标记中设置visit_id,可能在布局文件中的body标记中。
<body data-visit-id="<%= @visit.id %>">
Now read it from JS like this:
现在从JS中读:
document.querySelector('body').dataset.visitId
Your subscription creation line would look like this:
您的订阅创建线将如下所示:
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: document.querySelector('body').dataset.visitId)
#2
1
A few things to think about here:
这里有几点需要考虑:
- The order in which the scripts all load.
- 脚本全部装入的顺序。
- The specific timing of "instantiation" of the ruby variables, (Where / when they can be accessed).
- ruby变量的“实例化”的具体时间(在/何时可以访问它们)。
- Realizing that plain ol' JavaScript can be used within stupid CoffeeScript.
- 认识到简单的ol' JavaScript可以在愚蠢的CoffeeScript中使用。
That said - Here's the solution that worked for me:
这就是我的解决方案:
Files and Support
All of the files used in the question asked above are unchanged except for what's below. To get this working you'll need to reference the files above and the files below for the full stack.
上面问题中使用的所有文件都没有改变,除了下面的文件。要使此工作,您需要引用上面的文件和下面的文件以获得完整的堆栈。
The main template for my app: app/views/layouts/application.html.erb
Pay attention to the line within the head tag yield(:head_attributes)
我的应用程序的主要模板:app/视图/布局/应用。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>
The view for the page in which I am trying to use actioncable. In my case it's: app/views/visits/action_cable.html.erb
- Most times it will probably be your show.html.erb
or index.html.erb
Pay attention to the content_for
我尝试使用actioncable的页面的视图。在我的例子中是:app/view /visit / action_cabley .html。erb——大多数时候它可能是你的展示。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>
Then in my visit channel /app/assets/javascripts/channels/visit.coffee
然后在我的访问频道/app/资产/java脚本/频道/访问咖啡
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'
What's happening:
- As the page loads the view adds the data attribute of
data-visit-id
to the head of the page. - 当页面加载时,视图将数据访问id的数据属性添加到页面的头部。
- The channel of
visit.coffee
reads this attribute from the head of the page. - 访问的通道。coffee从页面的头部读取这个属性。
- Then
visit.coffee
can use this variable to subscribe to the appropriate channel. - 然后访问。coffee可以使用这个变量订阅适当的通道。
Other solutions wouldn't work because I was trying to access things in the wrong 'order' meaning, load a variable before it was instantiated. Hope this is helpful for others. This one stumped me for a solid 5 hours. ????
其他的解决方案不会起作用,因为我试图以错误的“顺序”访问东西,即在变量被实例化之前加载它。希望这对其他人有帮助。这件事让我为难了整整5个小时。????
#1
1
Set the visit_id
in a HTML tag, maybe in the body
tag in your layout file.
在HTML标记中设置visit_id,可能在布局文件中的body标记中。
<body data-visit-id="<%= @visit.id %>">
Now read it from JS like this:
现在从JS中读:
document.querySelector('body').dataset.visitId
Your subscription creation line would look like this:
您的订阅创建线将如下所示:
App.visit = App.cable.subscriptions.create (channel: 'VisitChannel', visit_id: document.querySelector('body').dataset.visitId)
#2
1
A few things to think about here:
这里有几点需要考虑:
- The order in which the scripts all load.
- 脚本全部装入的顺序。
- The specific timing of "instantiation" of the ruby variables, (Where / when they can be accessed).
- ruby变量的“实例化”的具体时间(在/何时可以访问它们)。
- Realizing that plain ol' JavaScript can be used within stupid CoffeeScript.
- 认识到简单的ol' JavaScript可以在愚蠢的CoffeeScript中使用。
That said - Here's the solution that worked for me:
这就是我的解决方案:
Files and Support
All of the files used in the question asked above are unchanged except for what's below. To get this working you'll need to reference the files above and the files below for the full stack.
上面问题中使用的所有文件都没有改变,除了下面的文件。要使此工作,您需要引用上面的文件和下面的文件以获得完整的堆栈。
The main template for my app: app/views/layouts/application.html.erb
Pay attention to the line within the head tag yield(:head_attributes)
我的应用程序的主要模板:app/视图/布局/应用。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>
The view for the page in which I am trying to use actioncable. In my case it's: app/views/visits/action_cable.html.erb
- Most times it will probably be your show.html.erb
or index.html.erb
Pay attention to the content_for
我尝试使用actioncable的页面的视图。在我的例子中是:app/view /visit / action_cabley .html。erb——大多数时候它可能是你的展示。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>
Then in my visit channel /app/assets/javascripts/channels/visit.coffee
然后在我的访问频道/app/资产/java脚本/频道/访问咖啡
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'
What's happening:
- As the page loads the view adds the data attribute of
data-visit-id
to the head of the page. - 当页面加载时,视图将数据访问id的数据属性添加到页面的头部。
- The channel of
visit.coffee
reads this attribute from the head of the page. - 访问的通道。coffee从页面的头部读取这个属性。
- Then
visit.coffee
can use this variable to subscribe to the appropriate channel. - 然后访问。coffee可以使用这个变量订阅适当的通道。
Other solutions wouldn't work because I was trying to access things in the wrong 'order' meaning, load a variable before it was instantiated. Hope this is helpful for others. This one stumped me for a solid 5 hours. ????
其他的解决方案不会起作用,因为我试图以错误的“顺序”访问东西,即在变量被实例化之前加载它。希望这对其他人有帮助。这件事让我为难了整整5个小时。????