【问题标题】:How do I tell rails not to precompile/cache a .js.erb file in my app?如何告诉 Rails 不要在我的应用程序中预编译/缓存 .js.erb 文件?
【发布时间】:2017-12-21 14:13:17
【问题描述】:

我的 app/assets/javascripts/channels 文件夹中有一个 messages.js.erb 文件,该文件应该生成代码以从数据库中获取每个聊天室并为该聊天室创建频道订阅。

这是我的 messages.js.erb 文件

//**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;
     }
  });
}

最好在每次创建新聊天室时重新加载此文件,但 rails 会在第一次加载后缓存(precompiling?)文件(asset?)并在每次请求时提供它。

所以,问题是:每次创建新聊天室时,如果我希望它进行流式传输(即,能够发布消息以立即流式传输到该聊天室的每个参与者),我需要手动更改文件(通过添加空格,或添加 cmets 或记录到控制台,something)并保存它,以便 rails 认为文件已更改并重新加载它,从而再次迭代所有包含新创建的聊天室的 Chatrooms .

否则,当我在尚未流式传输的聊天室中发布(按回车键)消息时(因为缓存版本看不到它),我得到一个

未捕获的类型错误:无法读取未定义的属性“setChatroomId” 在 HTMLTextAreaElement。 (messages.self-cbf13df66ead12b7956faa24e880ce07c0289634216a096fafd4ac1c6d262f43.js?body=1:436) 在 HTMLTextAreaElement.dispatch (jquery-1.11.3.min.self-ad66c584c2469d2bb527ba7aef5893549f1554ccc8ab3ccb43bd09ce8c3bf7a1.js?body=1:5) 在 HTMLTextAreaElement.r.handle (jquery-1.11.3.min.self-ad66c584c2469d2bb527ba7aef5893549f1554ccc8ab3ccb43bd09ce8c3bf7a1.js?body=1:5)

在我的浏览器控制台(开发者工具)中。错误的来源是:

这是生成的 messages.js 代码(为简洁起见,重复行被修剪)

  $(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;
     }
  });
}

我知道这个错误很明显,因为尚未为 ID 为 38 的新聊天室定义 App['room' + 38],我们试图在其中发布消息(此处为 ID 大于 37 的所有聊天室)

但是我如何让 rails 理解每次创建新聊天室时都需要重新加载此文件。如果不是每次,那么在每个请求中?基本上,告诉 Rails 不要预编译/缓存它,这样我就可以创建聊天室并随时随地从它们流式传输?

【问题讨论】:

    标签: javascript ruby-on-rails asset-pipeline actioncable precompile


    【解决方案1】:

    我猜你使用了来自https://www.thegreatcodeadventure.com/rails-5-action-cable-with-multiple-chatroom-subscriptions/ 的教程,这是一个很好的教程。 您应该通过更改预编译来解决此问题。相反,更有效地订阅频道。

    例如从外部执行方法。使用辅助方法仅获取所需的房间。

    subscripeToChannels(<%= raw chatrooms_for_client %>)
    

    在订阅方法中检查你是否还没有订阅。

    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;
        }
      }
    

    如果创建了新房间,您可以在 create.js.erb 文件中再次执行 subscipeToChannels。

    subscripeToChannels(<%= raw chatrooms_for_client %>)
    

    对我来说,这以更简洁的方式解决了它

    【讨论】:

      【解决方案2】:

      将您的messages.js.erb 文件移动到lib/assetsvendor/assets 目录。

      来自doc

      ...lib/assets 或 vendor/assets 下的资产可用于 通过应用程序清单包含但不再是 预编译数组。

      确保它没有在您的application.js 中列出,您应该一切顺利。

      【讨论】:

      • 如果我将文件移动到 lib/assets 或 vendor/assets,rails 根本不会加载它。所有聊天室停止流式传输
      • 这个question's 回答说,如果我想让rails 加载它,我需要明确要求lib(或供应商)资产中的文件。我这样做了,但后来我又遇到了同样的问题
      • @Rahul 嗯...据我了解,Sprockets 将从三个位置加载资产:app/assets、lib/assets 和 vendor/assets 根据需要。预编译只发生在 Rails > 3.2.6 的应用程序/资产上。当天晚些时候有时间时,我会对此进行更多研究,并希望建立一个有效的演示。我引用的文档似乎支持这种解释。
      猜你喜欢
      • 1970-01-01
      • 2013-12-15
      • 1970-01-01
      • 2019-10-07
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 2016-01-29
      • 2017-09-14
      相关资源
      最近更新 更多