我将Action Cable用于具有多种不同渠道的聊天应用程序。在Heroku上使用Redis和Postgresql(以保存消息)设置所有内容,95%的时间在开发和生产方面都非常有用。
有时,发送的邮件不会显示。消息被发送,它保存在数据库中,但除非我刷新,否则它永远不会出现在前端。或者,该消息显示在另一个未被定向的频道中。同样,一切都妥善保存在Postgres数据库中。它只是前端不稳定。在某个地方,ActionCable似乎感到困惑。
这个问题对我来说很少发生,很难复制到正确调试。但是我有很多用户经常报告这个问题,我很难弄清楚如何跟踪它。
以下是我的一些代码:
Javascript角/信道/ channels.js
class PodsChannel < ApplicationCable::Channel
def subscribed
stream_from "pods_channel_#{params['pod_slug']}"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def speak(data)
#after_create_commit callback fires to create a job to broadcast message
pod_message = PodMessage.create! pod_slug: data['pod_slug'], message_body: data['message'], user_id: data['user_id'], message_type: data['msg_type']
end
end
通道/ pods_channel.rb
$(document).on("ready",function(){
var pod_slug = $("#pod_slug_value").val();
// hack to prevent double posting of messages
if (!App.pods || JSON.parse(App.pods.identifier).pod_slug != pod_slug){
App.pods = App.cable.subscriptions.create(
{ channel: 'PodsChannel', pod_slug: pod_slug },
{
received: function(data) {
if ( ($(".chat-stream").length) && data.pod_slug == pod_slug ){ // hack to prevent msgs going accross pods
//#CLEAN: this is a super hackish way of preventing double messages
if(!$("#msg_" + data.msg_id).length){
$(data.message).appendTo($(".chat-stream")).find('.msg-text a').attr('target', '_blank');
$("#msg_" + data.msg_id + " .msg-text").html(Autolinker.link($("#msg_" + data.msg_id + " .msg-text").html(), { mention: "sutra" }));
$(".chat-stream").scrollTop($(".chat-stream")[0].scrollHeight);
}
}
},
speak: function(message, pod_slug, user_id, msg_type) {
return this.perform('speak',{
message: message,
pod_slug: pod_slug,
user_id: user_id,
msg_type: msg_type,
});
}
});
};
if ( $(".chat-stream").length ) {
$(".chat-stream").scrollTop($(".chat-stream")[0].scrollHeight);
};
captureMessage();
});
function captureMessage(){
$(document).on('click', "#btn-submit-msg", {}, function(){
var raw_text = $("#msg-input-text").val();
if (raw_text != ""){
submitMessage(raw_text, "pod_message");
}
});
$(document).on('keydown', '#msg-input-text', {}, function(event) {
if (event.which == 13 && !event.shiftKey && !event.ctrlKey && !event.metaKey) {
event.preventDefault();
event.stopPropagation();
if (event.target.value != "") {
submitMessage(event.target.value, "pod_message")
}
}
});
}
function submitMessage(raw_text, msg_type){
var message = raw_text;
var pod_slug = $("#pod_slug_value").val();
var user_id = $("#current_user_id_value").val();
var msg_type = msg_type;
if (App.pods.consumer.connection.disconnected == false) {
App.pods.speak(message, pod_slug, user_id, msg_type);
if (msg_type != "attachment") {
$("#msg-input-text").val("");
}
}
}
模型/ pod_message.rb
class PodMessage < ApplicationRecord
after_create_commit { MessageBroadcastJob.perform_now self }
end
作业/ message_broadcast_job.rb
class MessageBroadcastJob < ApplicationJob
queue_as :default
def perform(pod_message)
stream_id = "pods_channel_#{pod_message.pod_slug}"
ActionCable.server.broadcast stream_id, message: render_message(pod_message), msg_id: pod_message.id, pod_slug: pod_message.pod_slug
end
private
def render_message(pod_message)
renderer = ApplicationController.renderer.new
renderer.render(partial: 'pod_messages/pod_message', locals: { pod_message: pod_message })
end
end