In my project I have a model categories
, which has a detail view(show). The view contains data that should be updated in realtime with actioncable. The content/data of the view is not important to understand the problem.
A standart setup where I have just a single category with hardcoded id works perfectly, but now I want to make it dynamic and page specific, so that I don't need to open 100 subscriptions that I mabye do not even need if I'm not on a categories detail page.
First problem: how can I create connections for only the current page/category?
Second problem: how can I get the id of the current category?
App.cable.subscriptions.create { channel: "RankingChannel", category_id: HOW_DO_I_GET_THIS}
The only thing I found was this, but it did not work: https://stackoverflow.com/a/36529282/5724835
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
.
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).
$( 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:
<div id="category" data-category-id="<%= @category.id %>">
<div class="title">My Category</div>
...
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With