2

I'm using Rails5 to create an api provider to my application, and, I need use websocket.

Then, I created a very simple codes for tests:

routes.rb

Rails.application.routes.draw do

  mount ActionCable.server => '/cable'

  get '/testbroad', to: 'messages#testbroad'

end

messages_channel.rb

class MessagesChannel < ApplicationCable::Channel

  def subscribed
    stream_from 'messages'
  end

end

messages_controller.rb

class MessagesController < ApplicationController

  def testbroad
    ActionCable.server.broadcast('messages',
                                 message: 'foo')
    head :ok
  end

end

Then, I started the connection using cURL

➜  ~ curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: ws://localhost:3000/cable" http://localhost:3000/cable
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Location: ws://ws://localhost:3000/cable/cable

{"type":"welcome"}

It's work! But, when I try to send the broadcast...

➜  ~ curl http://localhost:3000/testbroad

The Rails' console show success, but, I not receive any message in cURL. Why I not received the message "foo"? How to resolve it?

macabeus
  • 4,156
  • 5
  • 37
  • 66

2 Answers2

1

After several hours, I found the problem.

This image is the Network debug in the page that started the WebSocket connection. enter image description here The table's first line show the message that browser send to server, {"command":"subscribe","identifier":"{\"channel\":\"MessagesChannel\"}"}.

After establish the connection, I need send a message with the channel that I want to subscribe. It's not write in the Rails' documention.

macabeus
  • 4,156
  • 5
  • 37
  • 66
1

I also want to understand this better, so basically you subscribed but you did not post any message. They key here was executing messages#testbroad

ActionCable.server.broadcast('messages',
                             message: 'foo')
head :ok

The subscription is set in the file app/channels/messages_channel.rb

I quote the documentation

3.2.2 Subscriptions

Consumers subscribe to channels, acting as subscribers. Their connection is called a subscription. Produced messages are then routed to these channel subscriptions based on an identifier sent by the cable consumer.

def subscribed
    stream_from 'messages'
end 

I believe it will be able to understand consumers that are subscribed to that channel

based on an identifier sent by the cable consumer

(the cable consumer is the one that reads from redis db). This way it understand the users that want to receive the notification and which are not anymore subscribed to the active channel, in app/assets/javascripts/channels/messages.js will trigger the App.cable.subscriptions.create('MessagesChannel') to post on the client front end the message.

App.cable.subscriptions.create('MessagesChannel', {      
  received: function(data) {
      $('#messages').append(this.renderMessage(data));
  },
  renderMessage: function(data) {
      return "<br><p> <strong>" + data.user + ": </strong>" + data.message + "</p>";
  }
});

I am posting the answer to discuss about ActionCable and get a better understanding. I know you already solved the issue..but I would like to discuss about this

It is still not clear to me!

Community
  • 1
  • 1
Fabrizio Bertoglio
  • 5,890
  • 4
  • 16
  • 57