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