Channels don't seem to be designed to be page specific (just as controllers are not page specific), but you can scope your channel (as you are trying to do) so that the subscription only receives messages for the given category.
You can selectively include the channel's js file on a page by putting something like this in the head of the layout file:
<%= javascript_include_tag 'channels/'+params[:controller] %>
rather than doing //= require_tree ./channels
in your cables.js
file.
but this has the disadvantage of requiring you to include the js file in the precompile array in your config\initializers\assets.rb
initializer and restarting your server:
Rails.application.config.assets.precompile += %w( channels/categories.js )
The channel definition is where you scope the stream, using stream_for
with a model, which makes the connection id unique, e.g., categories:Z2lkOi8vcmFpbHMtc3RaaaRlci9Vc2VyLzI
rather than just categories
.
app/channels/ranking_channel.rb
class RankingChannel < ApplicationCable::Channel
def subscribed
category = Category.find(params[:category_id])
stream_for category
end
...
end
You send the category_id
from the client page to the server. Here, we're doing it via a data-category-id
attribute on a #category
element in the DOM (using jQuery syntax, but could be converted to straight js pretty easily).
app/assets/javascripts/channels/categories.js
$( function() {
App.categories = App.cable.subscriptions.create(
{
channel: "RankingChannel",
category_id: $("#category").data('category-id')
},{
received: function(data) {
...
}
}
);
});
So in your view you would need to include the category id when the page is generated:
app/views/categories/show.html.erb
<div id="category" data-category-id="<%= @category.id %>">
<div class="title">My Category</div>
...
</div>