Search code examples
ruby-on-railscoffeescriptactioncable

ActionCable message saved but broadcast is ignored in after_create_commit


I'm using this ActionCable demo as a guideline for setting up user messaging, but I'm changing it so that there can be multiple private rooms between users. The message persists to the db through the speak method like so [ActionCable] [me] MessagesChannel#speak({"body"=>"eee", "conversation_id"=>1}) and then calls a background worker with an after_create_commit. The worker executes, but the broadcast is not broadcasting. What prevents that broadcast from executing?

2020-05-10T04:31:32.216Z pid=32378 tid=ouzv4m5h2 class=MessageBroadcastWorker jid=e8b23ada55bede39b811e770 INFO: start
2020-05-10T04:31:32.499Z pid=32378 tid=ouzv4m5h2 class=MessageBroadcastWorker jid=e8b23ada55bede39b811e770 elapsed=0.283 INFO: done

messages.coffee

if ($("meta[name='current-user']").length > 0)
  App.messages = App.cable.subscriptions.create "MessagesChannel",
    connected: ->
      console.log 'Connected'

    disconnected: ->
      console.log 'Disconnected'

    received: (data) ->
      console.log 'Received'

    speak: (body, conversation_id) ->
      @perform 'speak', body: body, conversation_id: conversation_id

  $(document).on 'turbolinks:load', ->
    submit_message()
    scroll_bottom()

  submit_message = () ->
    $('#response').on 'keydown', (event) ->
      if event.keyCode is 13
        conversation_id = $("#messages").data("conversation-id")
        App.messages.speak(event.target.value, conversation_id)
        event.target.value = ""
        event.preventDefault()

  scroll_bottom = () ->
    if $('#messages').length > 0
      $('#messages').scrollTop($('#messages')[0].scrollHeight)

messages_channel.rb

class MessagesChannel < ApplicationCable::Channel
  def subscribed
   #i have to change this so that the conversation id is a part of the stream but i'll do that later 
   stream_from "messages_channel"
  end

  def unsubscribed
    stop_all_streams
  end

  def speak(data)
   Message.create! body: data['body'], conversation_id: data['conversation_id'], user_id: current_user.id
  end
end

message.rb

class Message < ApplicationRecord
  after_create_commit { MessageBroadcastWorker.perform_async self.id }
end

message_broadcast_worker.rb

class MessageBroadcastWorker
 include Sidekiq::Worker

 def perform(message_id)
  message = Message.find message_id
  ActionCable.server.broadcast("messages_channel", message: render_message(message))
 end

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

views/messages/index.html.erb

<div id="messages" data-conversation-id="<%= @conversation.id %>">
 <%= render @messages %>
</div>
<%= form_for [@conversation, @message], remote: true do |f| %>
 <%= f.label :type_a_message %>
 <%= f.text_area :body, placeholder: "Say something.", autofocus: true, id:"response" %>            
<% end %>

views/messages/_message.html.erb

<% cache message do %>
 <div class="message">
  <div><strong><%= message.user.username %>:</strong> <%= message.body %></div>
  <div class="date"><%= local_time(message.created_at) %></div>
 </div>
<% end %>

Solution

  • i had two lines commented out in my config/cable.yml:

    development:
     adapter: redis
     url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
    

    adding those back in brought my app to life