Rails5 ActionCable Chat Chat

According to the DHCs Rails5 ActionCable chat example, I am going to create another example with dialogs and many messages there:

rails g model conversation class Conversation < ApplicationRecord has_many :messages end rails g model message content:text conversation:references 

View / talk / show.html.erb

 <h1>Conversation</h1> <div id="messages"> <%= render @messages %> </div> <form> <label>Say something:</label><br> <input type="text" data-behavior="conversation_speaker"> </form> 

View / Posts / _message.html.erb

 <div class="message"> <p><%= message.content %></p> </div> 

My questions are how to write channel logic so that every message related to his conversation is written to the database:

First I recorded a conversation and a message on the console

 Conversation.create Message.create(conversation_id: '1', content: 'hello') 

after that I created Job

 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 

and channel

 rails g channel conversation speak 

assets / javascripts / channels / conversation.coffee

 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 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() 

If I write:

Channels / conversation_channel.rb

 class ConversationChannel < ApplicationCable::Channel def subscribed stream_from "conversation_channel" end def speak Message.create! content: data['message'] end end 

I get

 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 

It looks fine, but if I type some text in the text box and hit return, I get:

 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' 

Any ideas?

+5
source share
1 answer

Starting from the client side on the server side, you must (first of all) force your speak function to accept the message parameter and send this message to the server as a JSON object.

 speak: (message) -> @perform 'speak', message: message 

Secondly, you need to determine the parameters obtained by the speak function on the / convers _channel.rb channels. Thus, you should redefine it as:

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

Now your speak method receives the data parameter, which is JSON with the message property, which contains the message sent to the server. It is written to the database, but there is no answer to those who subscribed to the channel.

Therefore, we must notify them of the method override above:

 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 

Now it should work. What you do in the background is up to you;)

+4
source

Source: https://habr.com/ru/post/1247378/


All Articles