Better ActionCable Errors
Eli Fatsi, Former Development Director
Article Categories:
Posted on
A simple monkey patch to make ActionCable errors readable
You know what's neat? Websockets. I'll admit I didn't see their potential beyond making chat applications until I started poking around with a project using a handrolled HTML-over-the-wire approach, and now I'm all in.
You know what's not neat? The default formatting that Rails's ActionCable kicks out whenever you hit a runtime error during the handling of a websocket request.
You know what else is neat? Monkey patching! I wouldn't be surprised if the error formatting got better in future releases of ActionCable. But until then, here's a little snippet of code you can drop into your project to get more readable ActionCable errors:
# in config/initializers/monkey_patches.rb
module BetterActionCableErrors
# This is replacing the default implementation for `execute_command`:
# https://github.com/rails/rails/blob/0ff395e1b115c91e286f694a0dbd136ddcde2f2a/actioncable/lib/action_cable/connection/subscriptions.rb#L15-L26
def execute_command(data)
case data["command"]
when "subscribe" then add data
when "unsubscribe" then remove data
when "message" then perform_action data
else
logger.error "Received unrecognized command in #{data.inspect}"
end
rescue Exception => e
@connection.rescue_with_handler(e)
logger.error ""
logger.error "\e[31m#{e.class} - #{e.message}\e[0m"
logger.error "Websocket command: \e[34m#{data.inspect}\e[0m"
project_name = Rails.root.to_s.split("/").last
e.backtrace.each do |trace_line|
if trace_line.include?(project_name)
logger.error trace_line
end
end
end
end
ActionCable::Connection::Subscriptions.prepend(BetterActionCableErrors)
The only thing new here, compared to the source, is the block below the rescue
call. Instead of logging everything out in one line and only outputting the first 5 backtrace lines, I output a blank line, the details of the error (in red of course), then the websocket request data, and finally all backtrace lines within your project directory, which cuts out about 25 boilerplate lines of things that look like this: /Users/efatsi/.asdf/installs/ruby/2.7.2/lib/ruby/gems/2.7.0/gems/actioncable-6.0.3.4/lib/action_cable/server/worker.rb:59:in 'block in invoke'
I added a raise
call in my code to demonstrate how errors look before:
Can you see the error in there? And how about that backtrace separated with
|
s?
And after:
Ahhhhh
I've submitted a Rails PR with this update and will see if they take it! But if not, hopefully you can just monkey patch this in and get yourself some better looking errors.