1

I believe I have set up Actioncable properly in my rails app on cloud9, but i can't seem to understand why the counter does not increase live and the message doesn't appear in the notification list automatically, if a user creates a comment on an article.

I am able to subscribe to the Notifications channel successfully.

Counter updates and notification gets rendered only after i reload the page, but I would like it to update automatically with Actioncable.

Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
  User Load (0.8ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 2], ["LIMIT", 1]]
Registered connection (Z2lkOi8vd2ViLWFwcC9Vc2VyLzI)
NotificationsChannel is transmitting the subscription confirmation
NotificationsChannel is streaming from notifications_channel

The broadcast job is enqueued, and message says the partials are rendered with the correct notification count and id.

Notification Load (1.1ms)  SELECT  "notifications".* FROM "notifications" WHERE "notifications"."id" = $1 LIMIT $2  [["id", 23], ["LIMIT", 1]]
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5] Performing NotificationBroadcastJob (Job ID: 7496ec3f-891b-47e2-b7e6-37d954aae3f5) from Async(default) with arguments: 22, #<GlobalID:0x007fa20330ec40 @uri=#<URI::GID gid://web-app/Notification/23>>
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5]   Rendered notifications/_counter.html.erb (0.6ms)
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5]   Comment Load (0.4ms)  SELECT  "comments".* FROM "comments" WHERE "comments"."id" = $1 LIMIT $2  [["id", 15], ["LIMIT", 1]]
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5]   Article Load (0.3ms)  SELECT  "articles".* FROM "articles" WHERE "articles"."id" = $1 LIMIT $2  [["id", 19], ["LIMIT", 1]]
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5]   User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5]   Rendered notifications/_notification.html.erb (7.0ms)
[ActiveJob] [NotificationBroadcastJob] [7496ec3f-891b-47e2-b7e6-37d954aae3f5] [ActionCable] Broadcasting to notification_channel: {:counter=>"<span class = \"glyphicon glyphicon-bell\"></span>\n<span id=\"notification-counter\">22</span>\n", :notification=>"  <div class = \"row\" data-notification-id= \"23\">\n    <div class= \"col-xs-10 col-md-10\">\n          <a href=\"/articles/si-ergo-lumen-quod\">\n            <li>Test1 posted a Comment on Si ergo lumen, quod </li> \n</a>    </div>\n    <div class= \"col-xs-2 col-md-2\">  \n      <a class=\"delete_notification\" data-remote=\"true\" rel=\"nofollow\" data-method=\"delete\" href=\"/notifications/23\">\n        <span class=\"glyphicon glyphicon-remove\"></span>\n</a>    </div>\n  </div>\n  <hr>\n"}

channels/notifications_channel.rb

class NotificationsChannel < ApplicationCable::Channel
  def subscribed
    stream_from "notifications_channel"
  end

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

javascripts/channels/notifications.coffee

App.notifications = App.cable.subscriptions.create "NotificationsChannel",

  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) ->
    # Called when there's incoming data on the websocket for this channel
    $('#notificationList').prepend "#{data.notification}"
    this.update_counter(data.counter)

  update_counter: (counter) ->
    $counter = $('#notification-counter')
    val = parseInt $counter.text()
    val++
    $counter
    .css({opacity: 0})
    .text(val)
    .css({top: '-10px'})
    .transition({top: '-2px', opacity: 1})

Notification broadcast job

class NotificationBroadcastJob < ApplicationJob
  queue_as :default

  def perform(counter,notification)
    ActionCable.server.broadcast 'notification_channel',  counter: render_counter(counter), notification: render_notification(notification)
  end

  private

  def render_counter(counter)
    ApplicationController.renderer.render(partial: 'notifications/counter', locals: { counter: counter })
  end

  def render_notification(notification)
    ApplicationController.renderer.render(partial: 'notifications/notification', locals: { notification: notification })
  end  

Notification model

class Notification < ApplicationRecord

    after_create_commit { NotificationBroadcastJob.perform_later(Notification.count, self)}

end

views:

navigation bar:

<%= render "notifications/notification_center", notifications: @notifications %>

_notification_center.html.erb:

<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
    <%= render 'notifications/counter', counter: notifications.count %>
</a>

<ul class="dropdown-menu" id="notificationContainer">
      <div id="notificationTitle">Notifications</div>
      <div id="notificationsBody">
        <ul id="notificationList">
          <%= render notifications %>
        </ul>
      </div>
      <div id="notificationFooter">
        <%= link_to notifications_path do %>
          Show More
        <% end %>
      </div>
</ul>

_counter.html.erb

<span id="notification-counter"><%= counter %></span>

_notification.html.erb

<li>Comment posted on <%= notification.notifiable.article.title %></li> 

UPDATE:

1) I do have to different channels, wondering if this is causing any problems with the subscription? I noticed that the 2 channels stop streaming when i click submit and before the comment gets committed to the database.

Started GET "/cable/" [WebSocket] for 103.252.202.198 at 2017-11-02 19:04:35 +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" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Registered connection (Z2lkOi8vd2ViLWFwcC9Vc2VyLzE)
NotificationsChannel is transmitting the subscription confirmation
NotificationsChannel is streaming from notifications_channel
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversations-1
Finished "/cable/" [WebSocket] for 103.252.202.198 at 2017-11-02 19:04:46 +0000
NotificationsChannel stopped streaming from notifications_channel
ConversationChannel stopped streaming from conversations-1
Started POST "/articles/quia-receperunt-merc/comments" for 103.252.202.198 at 2017-11-02 19:04:47 +0000
Cannot render console from 103.252.202.198! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by CommentsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"G1ygwktPQhsScBjGyr9bCz8aZMx8wC39aVG3NKmXtYkjSsbHnbygO1cmltLi/PtH4qVdbJaYorDkoV/xFPcPRA==", "comment"=>{"content"=>"why is it not updating live"}, "commit"=>"Add Comment", "article_id"=>"quia-receperunt-merc"}
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Article Load (0.4ms)  SELECT  "articles".* FROM "articles" WHERE "articles"."slug" = $1 LIMIT $2  [["slug", "quia-receperunt-merc"], ["LIMIT", 1]]
   (0.8ms)  BEGIN
  SQL (0.6ms)  INSERT INTO "comments" ("content", "article_id", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["content", "why is it not updating live"], ["article_id", 14], ["user_id", 1], ["created_at", "2017-11-02 19:04:47.088094"], ["updated_at", "2017-11-02 19:04:47.088094"]]
   (2.4ms)  COMMIT
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
   (0.1ms)  BEGIN
  SQL (1.1ms)  INSERT INTO "notifications" ("recipient_id", "actor_id", "action", "notifiable_id", "notifiable_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["recipient_id", 2], ["actor_id", 1], ["action", "posted"], ["notifiable_id", 14], ["notifiable_type", "Comment"], ["created_at", "2017-11-02 19:04:47.094991"], ["updated_at", "2017-11-02 19:04:47.094991"]]
   (1.9ms)  COMMIT
   (0.5ms)  SELECT COUNT(*) FROM "notifications"
[ActiveJob] Enqueued NotificationBroadcastJob (Job ID: ac5a005f-84d9-4ac8-be89-9f579732b167) to Async(default) with arguments: 13, #<GlobalID:0x007f10f0c6bc88 @uri=#<URI::GID gid://web-app/Notification/13>>
Redirected to https://test-site-dianaow.c9users.io/articles/quia-receperunt-merc
Completed 302 Found in 56ms (ActiveRecord: 8.7ms)

2) Upon checking in Chrome developer tool and following the steps here, I realized that there is no WebSocket message content after i submit the comment. Instead i get this constantly generating message: "type":"ping","message":1509650054}

3) I changed the adapter for development to Redis as i read that Redis is needed for multiple channels. However after running redis-server and restarting the rails server, I get a failed websocket connection message: WebSocket is closed before the connection is established. Am i setting up Redis wrongly?

cable.yml

production:
  adapter: redis
  url: <%= ENV["REDISCLOUD_URL"] %>

local: &local
  adapter: redis
  url: redis://127.0.0.1:6379/1

development: *local
test: *local

UPDATE 2:

Comments controller

  def create
    @comment = @article.comments.new(comment_params)
    @comment.user = current_user
      if @comment.save
        flash[:success] = "Your comment was created successfully"
        unless @comment.article.user == current_user
          Notification.create!(recipient: @article.user, actor: current_user, action: "posted", notifiable: @comment)
        end
        redirect_to @article
      else
        flash[:error] = "Unable to submit comment."
        redirect_to @article
      end
  end
doyz
  • 887
  • 2
  • 18
  • 43
  • Are you able to see the broadcast make it to the client? Chrome's Developer Tools let you see each frame for the cable, so you'd be able to see if your broadcast is making it to the client or not. – Daniel Westendorf Nov 02 '17 at 15:42
  • @DanielWestendorf No, the broadcast is not making to the client because the websocket message content does not appear after i submit a new comment. The streams seem to stop after i hit submit. – doyz Nov 02 '17 at 19:30
  • Is your form being submitted with AJAX? You'll need to prevent a page navigation to see same-page updates. – Daniel Westendorf Nov 02 '17 at 19:32
  • @DanielWestendorf Just posted the Comments Controller. No, the form is not submitted with Ajax. Once the comment is saved, a notification will be created and the page reloaded. – doyz Nov 02 '17 at 19:37
  • Your form will need to be a remote form and submitted with Ajax to prevent the channel from unsubscribing and therefore, never getting the update. – Daniel Westendorf Nov 02 '17 at 19:40

0 Answers0