首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rails5 ActionCable与对话聊天

Rails5 ActionCable与对话聊天
EN

Stack Overflow用户
提问于 2016-04-18 16:27:23
回答 1查看 1.8K关注 0票数 5

根据DHHs Rails5 ActionCable聊天示例,我将创建另一个包含对话和许多消息的示例:

代码语言:javascript
复制
rails g model conversation 

class Conversation < ApplicationRecord
  has_many :messages
end

rails g model message content:text conversation:references

查看/会话/show.html.erb

代码语言:javascript
复制
<h1>Conversation</h1>

<div id="messages">
  <%= render @messages %>
</div>

<form>
  <label>Say something:</label><br>
  <input type="text" data-behavior="conversation_speaker">
</form>

查看/消息/_message.html.erb

代码语言:javascript
复制
<div class="message">
  <p><%= message.content %></p>
</div>

我的问题是如何编写与对话相关的每条消息都写入数据库的通道逻辑:

首先,我在控制台上记录了一段对话和一条信息。

代码语言:javascript
复制
Conversation.create
Message.create(conversation_id: '1', content: 'hello')

后来我创造了一份工作

代码语言:javascript
复制
rails g job MessageBroadcast

class MessageBroadcastJob < ApplicationJob
  queue_as :default

  render_message(message)
  def perform(data)
    message = Message.create! content: data
    ActionCable.server.broadcast 'conversation_channel', message: render_message(message)
  end

  private
    def render_message(message)
      ApplicationController.renderer.render(partial: 'messages/message',
                                             locals: { message: message })
    end
end

和一个频道

代码语言:javascript
复制
rails g channel conversation speak

assets/javascripts/channels/conversation.coffee

代码语言:javascript
复制
App.conversation = App.cable.subscriptions.create "ConversationChannel",
  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) ->
    # Called when there's incoming data on the websocket for this channel
    $('#messages').append data['message']

  speak: ->
    @perform 'speak'

$(document).on 'keypress', '[data-behavior~=conversation_speaker]', (event) ->
  if event.keyCode is 13 # return = send
    App.conversation.speak event.target.value
    event.target.value = ""
    event.preventDefault()

如果我写:

频道/会话通道。

代码语言:javascript
复制
class ConversationChannel < ApplicationCable::Channel
  def subscribed
    stream_from "conversation_channel"
  end

  def speak
    Message.create! content: data['message']
  end
end

我得到了

代码语言:javascript
复制
Started GET "/cable/" [WebSocket] for ::1 at 2016-04-22 00:22:13 +0200
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: keep-a
live, Upgrade, HTTP_UPGRADE: websocket)
Started GET "/cable" for ::1 at 2016-04-22 00:22:13 +0200
Started GET "/cable/" [WebSocket] for ::1 at 2016-04-22 00:22:13 +0200
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: keep-a
live, Upgrade, HTTP_UPGRADE: websocket)
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversation_channel
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversation_channel

看起来没问题,但是如果我在textfield中输入了一些文本并按回车键,我会得到:

代码语言:javascript
复制
Could not execute command from {"command"=>"message", 
"identifier"=>"{\"channel\":\"ConversationChannel\"}", 
"data"=>"{\"action\":\"speak\"}"}) 
[NameError - undefined local variable or method `data' for #<ConversationChannel:0x00000008ad3100>]: 
C:/Sites/ActionCable/app/channels/conversation_channel.rb:13:
in `speak' | C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/actioncable-5.0.0.beta3/lib/action_cable/channel/base.rb:253:
in `public_send' | C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/actioncable-5.0.0.beta3/lib/action_cable/channel/base.rb:253:
in `dispatch_action' | C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/actioncable-5.0.0.beta3/lib/action_cable/channel/base.rb:163:
in `perform_action' | C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/actioncable-5.0.0.beta3/lib/action_cable/connection/subscriptions.rb:49:
in `perform_action'

有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-23 16:36:34

从客户端到服务器端,您必须(首先)使您的speak函数接受一个message参数,并将该消息作为JSON对象发送到服务器。

代码语言:javascript
复制
speak: (message) ->
  @perform 'speak', message: message

其次,您必须定义speak函数在信道/会话_channels el.rb上接收的参数。因此,必须将其重新定义为:

代码语言:javascript
复制
def speak(data)
  Message.create! content: data['message']
end

现在,您的speak方法正在接收一个data参数,它是一个带有message属性的JSON,该属性包含发送到服务器的消息。它正在被记录到数据库中,但是那些订阅频道的用户没有答案。

因此,我们必须通知他们,将上述方法重新定义为:

代码语言:javascript
复制
def speak(data)
  Message.create! content: data['message']
  ActionCable.server.broadcast 'conversation_channel', message: render_message(message)
end

private

def render_message(message)
  ApplicationController.renderer.render(partial: 'messages/message',
                                         locals: { message: message })
end

现在该起作用了。你在后台要做什么取决于你自己;)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36699451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档