如何在聊天应用中使用ActionController::Live和Resque + Redis?

7

我正在尝试为我的Rails应用程序构建聊天功能。 我使用,,,来实现这一点。 因此,在这种情况下,Redis 方法在后台使用运行。

到目前为止,我所做的就是每当用户在下面的表单字段即聊天框中输入文本时

    <%= form_tag chat_box_publish_path, method: :get do %>
        <%= text_field_tag :query, params[:query], class: "form-control", id: "chatSearchBox",
            placeholder: 'Search' %>
    <% end %>

请求正在发送到ChatBoxController中的Publish方法。

def publish
    $redis.publish("chat_message:1:1", "#{params[:query]}")
    respond_to do |format|
        format.js {render nothing: true}
    end
end

我现在有一个以下的背景任务 Resque 运行以下测试代码。因此,每当发布聊天消息时,它会打印 data,这很好。但是我怎样才能将 ActionController::Live 功能添加到后台作业?或者我该如何进行此实现?需要帮助解决此问题。

class ChatBoxInitiator
    @queue = :chat_box_initiator

    private
    def self.perform
    $redis.subscribe('chat_message:1:1') do |on|
            on.message do |event, data|
                puts "====#{data}"
                return data
            end
        end
    end
end

我希望您能够在Users/show页面上展示与ActionController::Live配合使用的Server Sent Events(SSE),以用于通知。


你在尝试做什么?如果你只是想要构建一个聊天 Web 应用程序,为什么需要使用 resqueresque 在其中的作用是什么? - Sheharyar
嘿@Sheharyar,实际上这是我的一个问题..我不确定我是否做得对..我正在尝试构建单页应用程序..主页面是users/show,我有ChatBoxController来使用redis并在users/show页面上更新..你有什么想法吗? - Rahul Dess
看看我的回答是否有帮助。 - Sheharyar
1个回答

13

前置条件:

  • Ruby 2.0.0+
  • Rails 4.0.0+
  • Redis
  • Puma

初始化器:

config/initializers目录中创建一个redis.rb初始化文件,将redis实例全局化。另外建议设置一个heartbeat线程(根据您的需求,从5秒到5分钟都可以):

$redis = Redis.new

heartbeat_thread = Thread.new do
  while true
    $redis.publish("heartbeat","thump")
    sleep 15.seconds
  end
end

at_exit do
  heartbeat_thread.kill
  $redis.quit
end

控制器:

您需要向您的ChatController添加两个方法:pubsubpub的作用是将聊天事件和消息发布到redis,而sub则订阅这些事件。应该看起来像这样:

class ChatController < ApplicationController
    include ActionController::Live

    skip_before_filter  :verify_authenticity_token

    def index
    end

    def pub
        $redis.publish 'chat_event', params[:chat_data].to_json
        render json: {}, status: 200
    end

    def sub
        response.headers["Content-Type"] = "text/event-stream"

        redis = Redis.new
        redis.subscribe(['chat_event', 'heartbeat']) do |on|
            on.message do |event, data|
                response.stream.write "event: #{event}\ndata: #{data}\n\n"
            end
        end
    rescue IOError
        logger.info "Stream Closed"
    ensure
        redis.quit
        response.stream.close
    end
end

在你的路由中,将pub设为POST,将sub设为GET,并将路径匹配为像/chat/publish/chat/subscribe这样的东西。


Coffeescript / Javascript:

假设你的聊天应用程序的实际网页位于/chat,你需要编写一些Javascript来发送和接收聊天消息。

为了方便理解,我们假设你的网页只有一个文本框和一个按钮。点击按钮应该将文本框的内容发布到聊天流中,我们可以使用AJAX来完成:

$('button#send').click (e) ->
    e.preventDefault()
    $.ajax '/chat/publish',
        type: 'POST'
        data:
            chat_data: {
                message: $("input#message").val()
                timestamp: $.now()
        error: (jqXHR, textStatus, errorThrown) ->
            console.log "Failed: " + textStatus 
        success: (data, textStatus, jqXHR) ->
            console.log "Success: " + textStatus

现在,你需要能够订阅并接收聊天消息。你需要使用EventSource来实现。使用EventSource开启SSE通道,以便可以接收事件,并使用该数据来更新视图。在这个例子中,我们只会将它们记录到Javascript控制台。

代码应该类似于:

$(document).ready ->
    source = new EventSource('/chat/subscribe')
    source.addEventListener 'chat_event', (e) ->
        console.log(e.data)

注意: 把上述两段代码块放入你的controllername.coffee文件中,对于这个示例,请把它放在你的app/assets/javascript目录下的chat.js.coffee文件中。你还需要确保它被加载到了资产管道中,并在你的application.js文件中require它(如果你还没有调用require tree .)。


启用并行请求:

在你的开发环境中,你需要在config/environments/development.rb文件中添加以下两行以启用并行请求:

config.preload_frameworks = true
config.allow_concurrency = true

现在打开你的浏览器,输入/chat并观看这个神奇的应用。当你输入一条消息并点击发送按钮时,该消息将被所有对应的网页实例接收。


以上就是使用ActionController::LiveRedisrails中创建一个基本聊天应用的方法。根据你的需求,最终代码可能会有所不同,但这应该可以帮助你入门。

以下还有一些你应该查看的资源:


嗨,在我的应用程序中,我只有一个页面,即users/show,在这个页面中,我有一个聊天框表单,就像我上面的问题所提到的那样。因此,当用户在其中发布聊天文本时,它会进入chat/publish控制器并进行发布。现在,另一个用户如何在users/show页面中收到新聊天消息的通知?如果我的问题不太清楚,请告诉我,因为我的解释能力有点差。 - Rahul Dess
@rahul,我理解了你的问题,我的答案正是如此。请查看JavaScript部分,了解其他用户如何接收聊天消息。 - Sheharyar
尽管我是凭记忆写下这个答案的,但我刚刚在我的本地机器上尝试了一下,并保证它可以正常工作。 - Sheharyar
嗨,对我来说它不起作用...在/users/show页面中提交我的聊天消息到/chat_box/publish,但是当chat_box#publish方法根本没有被调用时,我该如何在users/show中接收通知?在我的情况下,我应该将event source js放在用户视图中吗? - Rahul Dess
抱歉,我没有注意到你留下的评论,直到我随机回到这个答案。这是 coffeescript,你需要将它放在一个 chat.coffee 文件中,并在你的 application.jsrequire 它(如果你还没有使用 require tree .)。 - Sheharyar
1
@Sheharyar,非常感谢您详细的回答。特别感谢您提到的“启用并行请求”部分。我曾尝试使用Redis创建Rails聊天应用程序,但由于不了解并行请求功能,每次尝试时都会被阻止。 - elquimista

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接