I have a messages.js.erb file in my app/assets/javascripts/channels folder that should generate code to take each chatroom from the database and create channel subscriptions for that chatroom.
Here is my messages.js.erb file
//**app/assets/javascripts/channels/messages.js.erb**
$(document).on('turbolinks:load', function() {
submitNewMessage();
});
<% Chatroom.all.each do |chatroom| %>
App['room' + <%=chatroom.id%>] = App.cable.subscriptions.create({channel: 'MessagesChannel', room: <%=chatroom.id%>}, {
received: function(data) {
$("[data-chatroom='" + this.chatroomId + "']").removeClass('hidden');
return $("[data-chatroom='" + this.chatroomId + "']").append(data.message);
},
setChatroomId: function(chatroomId) {
this.chatroomId = chatroomId;
}
});
<% end %>
function submitNewMessage(){
//console.log(uid);
$('textarea#message_content').keydown(function(event) {
if (event.keyCode === 13) {
var msg = event.target.value;
var chatroomId = $("[data-chatroom]").data().chatroom;
var uid = $('#uid').val();
//console.log(uid);
App['room' + chatroomId].setChatroomId(chatroomId);
App['room' + chatroomId].send({message: msg, chatroom_id: chatroomId, user_id: uid});
$('[data-textarea="message"]').val(" ");
return false;
}
});
}
Preferably, this file should reload every time a new chatroom is created, but rails is caching(precompiling?
) the file(asset?
) after first load and serving it at every request.
So, the problem is: Every time a new chatroom is created, if I want it to stream (i.e., be able to post messages to be streamed instantly to every participant of that chatroom), I need to change the file manually (by adding whitespace, or adding comments or logging to console, something
) and save it so that rails thinks that the file has changed and reloads it, thereby iterating over all the Chatroom
s again which contains the newly created chatroom too.
Otherwise, when I post(hit enter) on a message in a chatroom that is not streaming yet (because the cached version can't see it) I get a
Uncaught TypeError: Cannot read property 'setChatroomId' of undefined at HTMLTextAreaElement. (messages.self-cbf13df66ead12b7956faa24e880ce07c0289634216a096fafd4ac1c6d262f43.js?body=1:436) at HTMLTextAreaElement.dispatch (jquery-1.11.3.min.self-ad66c584c2469d2bb527ba7aef5893549f1554ccc8ab3ccb43bd09ce8c3bf7a1.js?body=1:5) at HTMLTextAreaElement.r.handle (jquery-1.11.3.min.self-ad66c584c2469d2bb527ba7aef5893549f1554ccc8ab3ccb43bd09ce8c3bf7a1.js?body=1:5)
in my browser console (developer tools). The source of the error is:
Here is the generated messages.js code (repeat lines trimmed for brevity)
$(document).on('turbolinks:load', function() {
submitNewMessage();
});
App['room' + 1] = App.cable.subscriptions.create({channel: 'MessagesChannel', room: 1}, {
received: function(data) {
$("[data-chatroom='" + this.chatroomId + "']").removeClass('hidden');
return $("[data-chatroom='" + this.chatroomId + "']").append(data.message);
},
setChatroomId: function(chatroomId) {
this.chatroomId = chatroomId;
}
});
.
.
.
.
.
.
.
App['room' + 37] = App.cable.subscriptions.create({channel: 'MessagesChannel', room: 37}, {
received: function(data) {
$("[data-chatroom='" + this.chatroomId + "']").removeClass('hidden');
return $("[data-chatroom='" + this.chatroomId + "']").append(data.message);
},
setChatroomId: function(chatroomId) {
this.chatroomId = chatroomId;
}
});
function submitNewMessage(){
//console.log(uid);
$('textarea#message_content').keydown(function(event) {
if (event.keyCode === 13) {
var msg = event.target.value;
var chatroomId = $("[data-chatroom]").data().chatroom;
var uid = $('#uid').val();
App['room' + chatroomId].setChatroomId(chatroomId); // <-- line 436
App['room' + chatroomId].send({message: msg, chatroom_id: chatroomId, user_id: uid});
$('[data-textarea="message"]').val(" ");
return false;
}
});
}
I understand that this error is obvious, since App['room' + 38]
hasn't been defined yet for the new chatroom with id 38 in which we are trying to post the message (here, all chatrooms with id's > 37)
But how do I make rails understand that this file needs to be reloaded every time a new chatroom is created. If not every time, then on every request? Basically, tell rails not to precompile/cache it so I can create chatrooms and stream from them on the go?
I guess you used the tutorial from https://www.thegreatcodeadventure.com/rails-5-action-cable-with-multiple-chatroom-subscriptions/ which is a good one. You should solve this issue not with changing the precompile. Instead supscripe to the channels more efficiently.
For example execute the method from the outside. Use a helper method to get only the needed rooms.
subscripeToChannels(<%= raw chatrooms_for_client %>)
In the subscription method check if you do not subscribed already.
for (var i = 0; i < App.cable.subscriptions.subscriptions.length; i++) {
var s = App.cable.subscriptions.subscriptions[i]
var JSONObject = JSON.parse(s.identifier);
var room = JSONObject["room"];
if (room == chatroomId)
{
preventMultipleSubscripe = true;
}
}
In case a new room got created you can execute the subscripeToChannels again in your create.js.erb file.
subscripeToChannels(<%= raw chatrooms_for_client %>)
For me, this solved it in a cleaner way
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