混合redis actioncontroller :: live - rails app

时间:2014-03-04 10:06:25

标签: ruby-on-rails ruby redis chat

我第一次使用redis在我的rails应用中添加聊天功能,this

我有我的javascript`

$(document).ready ->
  source = new EventSource('/messages/events')
  source.addEventListener 'messages.create', (e) ->
    message = $.parseJSON(e.data).message
    console.log(message)
    $(".chat-messages").append "#some code"

并在我的消息控制器中

def create
    response.headers["Content-Type"] = "text/javascript"
    attributes = params.require(:message).permit(:content, :sender_id, :sendee_id)
    @message = Message.create(attributes)
    respond_to do |format|
      format.js { render 'messages/create.js.erb' }
    end
    $redis.publish('messages.create', @message.to_json)
  end

  def events
    response.headers["Content-Type"] = "text/event-stream"
    redis = Redis.new
    redis.subscribe('messages.*') do |on|
      on.message do |pattern, event, data|
        response.stream.write("event: #{event}\n")
        response.stream.write("data: #{data}\n\n")
      end
    end
  rescue IOError
    logger.info "Stream closed"
  ensure
    redis.quit
    response.stream.close
  end

问题是,首先,我的控制台中没有记录任何内容,其次我得到了大量随机ConnectionTimeoutError错误。有人想知道发生了什么

2 个答案:

答案 0 :(得分:2)

预REQS:

  • Ruby 2.0.0 +
  • Rails 4.0.0 +
  • Redis的
  • 彪马

初始化器:

redis.rb目录中创建config/initializers初始化文件,全球化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
  # not sure this is needed, but just in case
  heartbeat_thread.kill
  $redis.quit
end

控制器:

您需要向ChatControllerpubsub添加两种方法。 pub的作用是将聊天事件和消息发布到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']) 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

routes中,将 pub 设为POST sub a 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)

启用并行请求:

在您的开发环境中,您必须通过将这两行添加到config/environments/development.rb来启用并行请求:

config.preload_frameworks = true
config.allow_concurrency = true

现在启动浏览器,浏览到/chat并查看魔法。当您键入消息并单击该按钮时,该网页的所有实例都将收到该消息。


这就是您使用railsActionController::LiveRedis中制作基本聊天应用程序的方法。根据您的要求,最终的代码显然会有很大不同,但这应该可以帮助您入门。

您应该查看更多资源:

答案 1 :(得分:1)

虽然我没有使用redis这个容量(“实时”数据的调解员),但我设法让这个功能与Pusher一起使用


<强> Redis的

我不明白你是如何保持你的app&amp; Redis的。您需要某种Web套接字或并发连接技术来处理更新 - 据我所知,Redis不直接处理此问题

如果您查看this example,它会使用名为Goliath的服务器来处理asynchronous连接:

  

当微型聊天连接到服务器时,它会发送一个GET请求   / subscribe / everyone其中每个人都是频道的名称和   “Accept”标头设置为text / event-stream。流媒体中间件   (上面)收到此请求并订阅redis Pub / Sub   渠道。由于Goliath是非阻塞的,因此多个客户端都可以   在没有捆绑Heroku dyno的情况下聆听事件。一个有效载荷   服务器发送的事件如下所示:

基本上使用中间件将您连接到redis服务器 - 允许您根据需要接收更新


<强>代码

虽然我无法明确指出任何错误,但我可以给你一些我们正在使用的代码(使用Pusher):

    #config/initializers/pusher.rb
    Pusher.url = ENV["PUSHER_URL"]

    Pusher.app_id = ENV["PUSHER_APP_ID"]
    Pusher.key = ENV["PUSHER_KEY"]
    Pusher.secret = ENV["PUSHER_SECRET"]

    #app/controllers/messages_controller.rb
    def send_message
        id = params[:id]
        message = Message.find(id).broadcast!
        public_key = self.user.public_key
        Pusher['private-user-' + public_key].trigger('message_sent', {
            message: "Message Sent"
        })
    end

    #app/views/layouts/application.html.erb
    <%= javascript_include_tag "http://js.pusher.com/2.1/pusher.min.js" %>

    #app/assets/javascripts/application.js
    $(document).ready(function(){
    #Pusher
    pusher = new Pusher("************",
        cluster: 'eu'
    )

    channel = pusher.subscribe("private-user-#{gon.user}")
    channel.bind "multi_destroy", (data) ->
        alert data.message

    channel.bind "message_sent", (data) ->
        alert data.message
    });