Search code examples
javascriptruby-on-railsactioncable

How to keep a connection with a channel that uses paramaters passed from client to server for ActionCable?


I am not getting my head around actioncable.I want to allow users to subscribe to a PostChannel which looks like this,

class PostNotificationsChannel < ApplicationCable::Channel

  def subscribed
    stream_from params[:post_id]
  end

  def unsubscribed
    stop_all_streams
  end
end

Then I have the js

/javascripts/channels/post_notifications.js

$(document).on('turbolinks:load', function() {
  $("a.post_subscribe").click(function subscribeToPost() {
  var post_id = $(this).parents("li").attr("class").split(" ")[0]; // Get the post id off the page
  App.post_notifications = App.cable.subscriptions.create({channel: "PostNotificationsChannel", post_id: post_id}, {

    connected: function() {},

    disconnected: function() {},

    received: function(data) {}
    });
  });
});

So you click on the .post_subscribe anchor tag and it gets the value of that posts HTML class which I have on the page, then use that in the params hash of the subscription creation. This is all fine and dandy and the user who clicks this will get updates when some action happens on that post. But if you refresh the page then that connection cannot reconnect that consumer with that post as there is no parameters in the hash. So, I am wondering how do I get out of this.

Also, even on the rails guides page it shows this here So they are passing params over but how do you keep the connection when the page reloads?


Solution

  • So what I understand from your question is, you want the users to be a follower of that post when a user clicks on "subscribe" link. For this purpose, you will have to store this information in the database by having an association between User and Post as a Follower. Then whenever an activity happens on that post, broadcast a notification to the notifications stream of all the followers of that specific post.

    Create a NotificationsChannel to which each user will be subscribed to whenever he logs in to the site, so for example a User with id 1, logs in, he will be subscribed to a notifications stream which will be unique to each user e.g. notify_user_1_channel

    class NotificationsChannel < ApplicationCable::Channel
      def subscribed
        if params[:recepient].present?
          stream_from "notify_#{params[:recepient]}_channel"
        end
      end
    
      def unsubscribed
        # Any cleanup needed when channel is unsubscribed
      end
    end
    

    In your script for channel,

    App.chat = App.cable.subscriptions.create {
                channel: "NotificationsChannel"
                recepient: $('#recepient').data("recepient")
                }
    

    And for giving the recepient as a parameter, in view code somewhere, preferably in footer,

    <div id="recepient" data-recepient="User_<%= current_user.id %>"></div>
    

    And, for broadcasting the notification to a stream, in after_create_commit of notification model,

    ActionCable.server.broadcast "notify_#{notification.recepient_type}_#{notification.recepient_id}_channel"