ruby-on-rails - 如何在 heroku 上部署 Action 电缆?

标签 ruby-on-rails redis actioncable

您好,我已经使用 rails 5 实现了 action cable。它在本地工作正常,但在 heroku 上不工作。在 heroku 上,每当我发送任何消息时,它都会发送四条消息,两条重复消息和两条空白消息。这是我的代码:- 对话.js

 App.conversation = App.cable.subscriptions.create("ConversationChannel", {
      connected: function() {},
      disconnected: function() {},
      received: function(data) {
        var conversation = $('#conversations-list').find("[data-conversation-id='" + data['conversation_id'].$oid + "']");
        if (data['window'] !== undefined) {
          var conversation_visible = conversation.is(':visible');

          if (conversation_visible) {
            var messages_visible = (conversation).find('.panel-body').is(':visible');

            if (!messages_visible) {
              conversation.removeClass('panel-default').addClass('panel-success');
              conversation.find('.panel-body').toggle();
            }
            conversation.find('.messages-list').find('ul').append(data['message']);
          }
          else {
            $('#conversations-list').append(data['window']);
            conversation = $('#conversations-list').find("[data-conversation-id='" + data['conversation_id'].$oid + "']"); 
            conversation.find('.panel-body').toggle();
          }
        }
        else {
          conversation.find('ul').append(data['message']);
        }

        var messages_list = conversation.find('.messages-list');
        var height = messages_list[0].scrollHeight;
        messages_list.scrollTop(height);
      },
      speak: function(message) {
        return this.perform('speak', {
          message: message
        });
      },
    });

$(document).on('submit', '.new_message', function(e) {
  e.preventDefault();
  var values = $(this).serializeArray();
  App.conversation.speak(values);
  $(this).trigger('reset');
});

应用程序.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
// require turbolinks
//= require jquery-3.2.1.min
// require_tree .

(function() {
  $(document).on('click', '.toggle-window', function(e) {
    e.preventDefault();
    var panel = $(this).parent().parent();
    var messages_list = panel.find('.messages-list');

    panel.find('.panel-body').toggle();
    panel.attr('class', 'panel panel-default');

    if (panel.find('.panel-body').is(':visible')) {
      var height = messages_list[0].scrollHeight;
      messages_list.scrollTop(height);
    }
  });
})();

电缆.js

//= require action_cable
    //= require_self
    //= require_tree ./channels

        (function() {
          this.App || (this.App = {});

          App.cable = ActionCable.createConsumer();

        }).call(this);

创建.js

var conversations = $('#conversations-list');
var conversation = conversations.find("[data-conversation-id='" + "<%= @conversation.id %>" + "']");

        if (conversation.length !== 1) {
          conversations.append("<%= j(render 'conversations/conversation', conversation: @conversation, user: current_user) %>");
          conversation = conversations.find("[data-conversation-id='" + "<%= @conversation.id %>" + "']");
        }

        conversation.find('.panel-body').show();

        var messages_list = conversation.find('.messages-list');
        var height = messages_list[0].scrollHeight;
        messages_list.scrollTop(height);

聊天截图 enter image description here

请告诉我如何修复它。我将 Rails 5 与 ruby​​-2.4.0 一起使用。我也在使用 Redis 服务器进行作业。

最佳答案

您设置了一个与 ActionCable 无关的 Javascript event 监听器。

每次触发submit 底部时,您都会调用App.conversation.speak() 函数将消息附加到页面上

$(document).on('submit', '.new_message', function(e) {
  e.preventDefault();
  var values = $(this).serializeArray();
  App.conversation.speak(values);
  $(this).trigger('reset');
});

这是你的speak函数

speak: function(message) {
   return this.perform('speak', {
     message: message
   });

我引用 Defining The Channel's Subscriber

We add our new subscription to our consumer with App.cable.subscriptions.create. We give this function an argument of the name of the channel to which we want to subscribe, ConversationChannel.

When this subscriptions.create function is invoked, it will invoke the ConversationChannel#subscribed method, which is in fact a callback method.

So what is a callback method?这个问题我回答不清楚。

This method is responsible for subscribing to and streaming messages that are broadcast to this channel.

app/channels/conversation_channel.rb

class ConversationChannel < ApplicationCable::Channel  
  def subscribed
    stream_from 'conversation'
  end
end  

那个

ConversationChannel#subscribed streams from our messages broadcast, sending along any new messages as JSON to the client-side subscription function.

这就是我实现 ActionCable 的方式,在 Message 保存到数据库后,我在我的 MessagesController 中触发以下操作,如 Sophie Debenedetto指南(我不知道你是保存一个Conversation到数据库还是一个Message)

app/controllers/messages_controller.rb

class MessagesController < ApplicationController

  def create
    message = Message.new(message_params)
    message.user = current_user
    if message.save
      ActionCable.server.broadcast 'messages',
        message: message.content,
        user: message.user.username
      head :ok
    end
  end

  ...
end

ActionCable.server.broadcast 'messages',App.cable.subscription 中的 received 函数发送调用,该函数是负责用新消息更新页面。

此调用只会对订阅此事件的用户执行。订阅在 ConversationChannel

subscribed 方法中管理
App.conversation = App.cable.subscriptions.create('ConversationChannel', {      
  received: function(data) {
      $('#messages').append(this.speak(data));
      },
  speak: function(data) {
      return "<br><p> <strong>" + data.user + ": </strong>" + data.message + "</p>";
      };
  }
});

它以 json 格式从您的 Rails Controller 传递了以下数据 message: message.content, user: message.user.username

部分代码取 self 的应用 https://sprachspiel.xyz那是您可以测试的 Action 电缆应用程序,该应用程序应该仍在运行。这是 github repository

我相信您正在调用您的 js 函数两次,或者正在做一些变通方法来使 actioncable 工作,从而导致 div 被附加两次。我相信您正在执行 2 个不同的时间 js 来运行 Action 电缆。

请记住,action cable 是一个 websocket,用于在 2 个不同的用户/浏览器上更新该消息

关于ruby-on-rails - 如何在 heroku 上部署 Action 电缆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47221089/

相关文章:

ruby-on-rails - Gem::installerror: 'json' native gem 需要安装构建工具。请更新我们的路径以包含构建工具

c# - 任何 (.NET) Redis SessionStore 库?

python - 从 Python 设置的 Redis 值未反射(reflect)在 redis 客户端中

ruby-on-rails - ActionCable 未接收数据

ruby-on-rails - Action 电缆检测多个连接/选项卡

ruby-on-rails - 在Rails中进行RTF编辑的最佳选择是什么?

ruby-on-rails - 在 ruby 中是否有安全的 Eval 方法?或者更好的方法来做到这一点?

ruby-on-rails - 未定义的方法 `new_confirmation_path' 确认模块设计 + MongoID

ruby - 如何使用redis ruby​​计算redis中的set complement操作?

devise - ActionCable 中的多个连接