我正在努力使用动作电缆。在我的情况下,我有几个用户(通过Devise
)可以相互分享任务。
现在,当user#1
与user#2
共享任务(通过表单)时,所有经过身份验证的用户都会收到通知。
我应该如何以及在何处确定我的user#2
仅向他广播?
到目前为止,这是我的代码:
connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.id
end
protected
def find_verified_user # this checks whether a user is authenticated with devise
if verified_user = env['warden'].user
verified_user
else
reject_unauthorized_connection
end
end
end
end
cable.js
(function() {
this.App || (this.App = {});
App.cable = ActionCable.createConsumer();
}).call(this);
todo_channel.rb
class TodoChannel < ApplicationCable::Channel
def subscribed
stream_from "todo_channel_#{current_user.id}"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def notify
ActionCable.server.broadcast "todo_channel_#{current_user.id}", message: 'some message'(not implemented yet)
end
end
todo.coffee
App.todo = App.cable.subscriptions.create "TodoChannel",
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['message'])
notify: ->
@perform 'notify'
答案 0 :(得分:5)
我之前遇到过类似的事情,直到我意识到您可以在频道中多次拨打stream_from
并且该用户将订阅多个不同的&#34;房间&#34;在同一频道连接中。这意味着你基本上可以做到这一点
class TodoChannel < ApplicationCable::Channel
def subscribed
stream_from "todo_channel_all"
stream_from "todo_channel_#{current_user.id}"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def notify(data)
# depending on data given from the user, send it to only one specific user or everyone listening to the "todo_channel_all"
if data['message']['other_user_id']
ActionCable.server.broadcast "todo_channel_#{data['message']['other_user_id']}", message: 'some message'
else
ActionCable.server.broadcast "todo_channel_all", message: 'some message'
end
end
end
该代码假设用户已经知道其他用户的ID并将其发送到频道,您可能需要用一些安全性或其他东西来包装,我承认我没有很好的经验因为我还在学习。
将来可能对您有益的其他事实是您还可以在同一频道功能中广播多个消息/次。这意味着您可以支持将您的任务发送给单个特定用户,特定用户列表或每个人。只需迭代列表/数组/用户的任何内容,并在他们的个人&#34; todo_channel _#{user.id}&#34;上广播任务/消息/通知/任何内容。
答案 1 :(得分:3)
我最后采用了不同的方法。我会在这里写,以防有人发现它有用。
通知具有必须通知的用户的ID。所以在模型中我有:
def paraula(file,palabrabuscar):
abrirLetra = open(file) #Open the file
palabras = ""
vegades = 0
for palabras in abrirLetra.read().split():#I split all words in text
if (palabras == palabrabuscar) :#Look for coincidence
vegades = vegades +1
abrirLetra.close()
return vegades
file = 'lletra.txt'
print paraula(file,"you")
当我将广播放入模型时,after_commit :broadcast_notification, on: :create
def broadcast_notification
ActionCable.server.broadcast "todo_channel_#{self.user_id}", message: 'some message'
end
看起来像这样:
todo_channel.rb
答案 2 :(得分:1)
步骤1:让每个用户拥有唯一的会话令牌。订阅时,每个用户都将在标头中发送会话令牌,并且可以在连接类中访问标头。使用会话令牌查找用户。
步骤2:在用户ID上串流用户。
步骤3:在共享任务时,在请求中也获取用户ID,并以给定的用户ID广播。
答案 3 :(得分:1)
这称为&#34;私人聊天&#34;。如果您真的想获得current_user.id
,可以通过以下三种方式完成:
从onload
到服务器的一些AJAX todo.coffee
来电。
在Rails HTML视图中将current_user.id
渲染为属性,然后通过todo.coffee
内的jQuery获取(如https://www.sitepoint.com/create-a-chat-app-with-rails-5-actioncable-and-devise/中所示)
在用户登录时创建纯Cookie,然后在todo.coffee
但你不应该使用current_user.id
,因为它不安全。如果你使用它,那么有人可能会在同一个网站注册,并轻松听取其他用户的意见。私密聊天只需提供随机user_id
。
而是使用签名(例如Rails加密)cookie作为用户的唯一广播标识符。这样,如果您在同一网站注册,您将永远不会知道其他用户的签名cookie - 因此您无法进入外来私人聊天。
应用/配置/初始化/ warden_hooks.rb 强>
请参阅https://rubytutorial.io/actioncable-devise-authentication/
# Be sure to restart your server when you modify this file.
Warden::Manager.after_set_user do |user,auth,opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = user.id
end
Warden::Manager.before_logout do |user, auth, opts|
scope = opts[:scope]
auth.cookies.delete("#{scope}.id")
end
<强> todo_channel.rb 强>
class TodoChannel < ApplicationCable::Channel
def subscribed
stream_from "todo_channel_#{params['user_signed_cookie']}"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def notify(param_message)
ActionCable.server.broadcast "todo_channel_#{param_message['user_signed_cookie']}", message: 'some message'(not implemented yet)
end
end
<强> todo.coffee 强>
user_signed_cookie = document.cookie.replace(/(?:(?:^|.*;\s*)user.id\s*\=\s*([^;]*).*$)|^.*$/, "$1");
user_logged_in = if user_signed_cookie then true else false
if user_logged_in #avoid repetitive HTTP->WebSockets upgrade pointless browser attempts when no user logged in.
App.todo = App.cable.subscriptions.create {
channel:"TodoChannel"
user_signed_cookie: user_signed_cookie
},
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['message'])
notify: (name, content, _) -> #name, content - message fields
@perform 'notify', name: name, content: content, user_signed_cookie: user_signed_cookie