I'm attempting to send data to a Rails application from a client that I'm not able to modify. The client sends a Websocket request with only the data "requestTime", which the Rails server then receives. When receiving the request, the Rails should read the data as string value, but for some reason it's being parsed to JSON without my explicit input. How would I either disable the JSON parsing, or allow the code to work without modifying the client? The WS broadcast must also be raw string/number It seems as if ActionCable must use JSON no matter what, at least according to different posts I've seen.
It's really frustrating as after almost a week I haven't been able to implement an app that is really close to just being an "echo broadcast" interface. If ActionCable must use JSON, are there any other possibilities to use raw WebSocket data on Rails?
Thrown error
Started GET "/clock" for 127.0.0.1 at 2023-03-10 21:44:58 +0200
Started GET "/clock/" [WebSocket] for 127.0.0.1 at 2023-03-10 21:44:58 +0200
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
There was an exception - JSON::ParserError(859: unexpected token at 'requestTime')
There was an exception - JSON::ParserError(859: unexpected token at 'requestTime')
C:/Ruby31-x64/lib/ruby/3.1.0/json/common.rb:216:in `parse'
C:/Ruby31-x64/lib/ruby/3.1.0/json/common.rb:216:in `parse'
C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/activesupport-7.0.4.2/lib/active_support/json/decoding.rb:23:in `decode'
C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/actioncable-7.0.4.2/lib/action_cable/connection/base.rb:168:in `decode'
C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/actioncable-7.0.4.2/lib/action_cable/connection/base.rb:89:in `dispatch_websocket_message'
...
...
Implemented code
app/channels/clock_channel.rb
class ClockChannel < ApplicationCable::Channel
def subscribed
stream_from "clock_channel"
end
# \/ THROWS Json::ParseError(unexpected token at 'requestTime')
def receive(data)
if data == "requestTime"
ActionCable.server.broadcast "clock_channel", Time.now
end
end
end
config/routes.rb
Rails.application.routes.draw do
mount ActionCable.server => '/clock'
end
Example how the client sends the message (NodeJS)
import ws from 'ws';
const client = new ws("ws://localhost:3000/clock");
client.on('open', () => {
client.send("requestTime");
});