Search code examples
ruby-on-railsrubycloud9-ideactioncable

Trouble understanding ActionCable


I have been looking at ActionCable for a few days and I'm finding it hard to digest how to use it. After looking at various examples, watching YouTube videos and reading some of the Ruby Edge Guides I'm still not sure on how to implement it to my project.

What I'm trying to do is get the top 20 results from my Broadcasts table and place them into the 'feed' div from the application.html.erb here is the code for that div:

<div class="content">
  <div id="feed">
    <h1>TEST</h1>
  </div>
  <%= yield %>
</div>

I have included this in my 'routes.rb':

mount ActionCable.server => '/cable'

This is 'feeds.coffee':

App.feeds = App.cable.subscriptions.create "FeedsChannel",
  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) -> 
    $(".content #feed").append(data);
    # Called when there's incoming data on the websocket for this channel

And here is 'feeds_channel.rb':

# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
class FeedsChannel < ApplicationCable::Channel
  def subscribed
        messages = Broadcast.all
       stream_for messages
       ActionCable.server.broadcast("FeedsChannel", messages.last(20))
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end

I'm obviously doing something stupid here and can't work out where. Here is a printout from the console output

=> Booting Puma
=> Rails 5.0.0.1 application starting in development on http://0.0.0.0:8080
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.6.2 (ruby 2.3.0-p0), codename: Sleepy Sunday Serenity
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:8080
Use Ctrl-C to stop
Started GET "/" for 144.124.4.228 at 2016-11-24 12:13:51 +0000
Cannot render console from 144.124.4.228! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
  ActiveRecord::SchemaMigration Load (1.8ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by HomeController#index as HTML
  Rendering home/index.html.erb within layouts/application
  Rendered home/index.html.erb within layouts/application (2.2ms)
  Rendered sessions/_login.html.erb (1.8ms)
Completed 200 OK in 709ms (Views: 692.0ms | ActiveRecord: 0.0ms)


Started GET "/cable" for 144.124.4.228 at 2016-11-24 12:13:54 +0000
Cannot render console from 144.124.4.228! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Started GET "/cable/" [WebSocket] for 144.124.4.228 at 2016-11-24 12:13:54 +0000
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 41], ["LIMIT", 1]]
Registered connection (Z2lkOi8vY3NhL1VzZXIvNDE)
  Broadcast Load (2.0ms)  SELECT  "broadcasts".* FROM "broadcasts" ORDER BY "broadcasts"."id" DESC LIMIT ?  [["LIMIT", 20]]
[ActionCable] Broadcasting to FeedsChannel: [#<Broadcast id: 38, content: "Hello From APP!!!\n", user_id: 41, created_at: "2016-11-18 16:24:38", updated_at: "2016-11-18 16:24:38">, #<Broadcast id: 39, content: "Hello from MrPaul's App\n", user_id: 41, created_at: "2016-11-18 18:07:41", updated_at: "2016-11-18 18:07:41">, #<Broadcast id: 40, content: "New app test 2", user_id: 41, created_at: "2016-11-18 18:09:13", updated_at: "2016-11-18 18:09:13">, #<Broadcast id: 41, content: "ALALLALALALALA", user_id: 41, created_at: "2016-11-18 19:13:40", updated_at: "2016-11-18 19:13:40">, #<Broadcast id: 42, content: "LALALA TETS", user_id: 41, created_at: "2016-11-18 19:19:09", updated_at: "2016-11-18 19:19:09">, #<Broadcast id: 43, content: "Tets from app fro feeds", user_id: 41, created_at: "2016-11-18 19:37:38", updated_at: "2016-11-18 19:37:38">, #<Broadcast id: 44, content: "fsfsdf", user_id: 41, created_at: "2016-11-18 19:38:14", updated_at: "2016-11-18 19:38:14">, #<Broadcast id: 45, content: "Test from app tesrers", user_id: 41, created_at: "2016-11-18 19:38:48", updated_at: "2016-11-18 19:38:48">, #<Broadcast id: 46, content: "lalalalal", user_id: 41, created_at: "2016-11-21 17:26:55", updated_at: "2016-11-21 17:26:55">, #<Broadcast id: 47, content: "cdsc", user_id: 41, created_at: "2016-11-21 17:51:25", updated_at: "2016-11-21 17:51:25">, #<Broadcast id: 48, content: "nohonnl", user_id: 41, created_at: "2016-11-21 18:12:22", updated_at: "2016-11-21 18:12:22">, #<Broadcast id: 49, content: "rewrewwrwr", user_id: 41, created_at: "2016-11-22 12:45:16", updated_at: "2016-11-22 12:45:16">, #<Broadcast id: 50, content: "sefewr", user_id: 41, created_at: "2016-11-22 14:45:19", updated_at: "2016-11-22 14:45:19">, #<Broadcast id: 51, content: "fdsfdsfsd", user_id: 41, created_at: "2016-11-22 16:41:04", updated_at: "2016-11-22 16:41:04">, #<Broadcast id: 52, content: "trrretretr", user_id: 41, created_at: "2016-11-22 17:40:20", updated_at: "2016-11-22 17:40:20">, #<Broadcast id: 53, content: "fdsfsdfsd", user_id: 41, created_at: "2016-11-22 17:47:05", updated_at: "2016-11-22 17:47:05">, #<Broadcast id: 54, content: "fdsds", user_id: 41, created_at: "2016-11-22 18:05:17", updated_at: "2016-11-22 18:05:17">, #<Broadcast id: 55, content: "fdsfs", user_id: 41, created_at: "2016-11-22 18:23:44", updated_at: "2016-11-22 18:23:44">, #<Broadcast id: 56, content: "iyuirriry", user_id: 41, created_at: "2016-11-22 18:32:00", updated_at: "2016-11-22 18:32:00">, #<Broadcast id: 57, content: "fdsfsfs", user_id: 41, created_at: "2016-11-23 15:23:08", updated_at: "2016-11-23 15:23:08">]
FeedsChannel is transmitting the subscription confirmation

I have looked in the console and done a bit of digging client side and find when I type 'App.feeds.received.data' it comes back as 'undefined' what parts am I missing to get this working? Thanks.


Solution

  • I don't think you should be broadcasting from the subscribed method. All you should need there is:

    def subscribed
       stream_from "feed"
    end
    

    On page load, you should just render all Broadcast messages you'd like within the feed div when the page is initially rendered, and then you broadcast to all clients if anything is added to the feed. If all clients are subscribed to and streaming from "feeds" it should be updated within each clients browser.

    On the server side wherever you've created a new Broadcast object (likely within the model or controller), just add:

    ActionCable.server.broadcast "feed", messages: new_broadcast_object
    

    Action Cable is sending JSON, so you can't send straight up ruby objects through the web socket and append the data in client side javascript. Make sure that your message is an html string, or convert your new_broadcast_object object to JSON if you need to manipulate it client side.