Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I tell rails not to precompile/cache a .js.erb file in my app?

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 Chatrooms 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?

like image 640
Rahul Avatar asked Oct 18 '22 01:10

Rahul


1 Answers

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

like image 195
Alexander Bahlk Avatar answered Oct 21 '22 08:10

Alexander Bahlk