Rails - 搞清楚javascript配置

时间:2016-12-11 02:20:39

标签: javascript ruby-on-rails google-maps heroku production-environment

我已经苦苦挣扎了4年,想出如何在我的Rails应用程序中使用谷歌地图。

我尝试过使用gmaps4rails,但放弃了,因为它太难了。我设法在SO上找到了一个解决方案,除了我无法指定缩放级别之外。但是,在制作中,我所有的其他javascripts都没有用。解决方案是移动:

<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

从头部标签和身体标签的底部。

这样可以让我的所有其他js文件像在开发环境中那样运行,但是在生产模式下,现在地图根本不会渲染。

是否有解决方案:

  1. 允许我使用我的javascript文件(谷歌地图js文件除外) - 我认为这是通过在身体末端使用javascript include标签而不是头部来实现的

  2. 允许我在制作中渲染谷歌地图?如果我将javascript include标记移回头部,我可以渲染地图,但我的其他js文件不起作用(仅在生产中)。

  3. 允许我在地图上指定缩放级别吗?

  4. 我曾尝试过寻求帮助hereherehere(以及其他一百万次)。我还没有找到帮助。

    在我的address.js中,我有:

    function initMap() {
      var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 5
      });
      var bounds = new google.maps.LatLngBounds();
      // var opts = {
      //   zoom: 10,
      //   max_zoom: 16
      // }
    
      var n = addresses.length;
      for (var i = 0; i < n; i++) {
        var lat = addresses[i].latitude;
        var lng = addresses[i].longitude;
        if (lat == null || lng ==null){
          console.log(addresses[i].name + " doesn't have coordinates");
        }else {
          var address = new google.maps.Marker({
            position: {lat: parseFloat(lat), lng: parseFloat(lng)},
            title: addresses[i].name,
            map: map //,
    //        zoom: 8
          });
          bounds.extend(address.position);
        }
      }
      map.fitBounds(bounds);
    }
    

    正如我在post中所述,我收到一条错误消息:

    initMap is not a function
    

    我已经标记了所有相关帖子,这些帖子提供了该帖子中的解决方案,以及我努力使用这些解决方案解决问题的结果。

    关于地图上的缩放级别,this post中的答案将问题解释为可归因于js要求包含其中每个地址的地图。无论我试图指定哪个级别,都会以某种方式强制缩放级别放大最多。所以有两个问题,第一个是如何删除强制放大最多的位,以便我可以设置一个将被确认的缩放级别,第二个是表示缩放的方式是否有一些变化等级,因为SO上的这么多答案(包括我在帖子中链接的那些)建议使用&#34; setZoom&#34;而不是&#34; zoom:5&#34;。我无法找到有效的解决方案。

    正如我在this post中所述,如果我在头部有javascript include标记,则js文件(谷歌地图除外)不会在制作中工作。经过长期昂贵的代码编制会议后,我才得到了这个解决方案。我无法负担另一个会议,以了解如何解决此解决方案所创建的问题。我也没有得到关于为什么这种改变是必要的根本原因的解释。导轨指南建议将它包含在那里,所以我不明白为什么,在大多数情况下,将它移动到body标签的末尾是一个让js在生产环境中工作的解决方案。这打破了地址js,因此它不是正确的解决方案

    在我的config.rb中我有

    config/initializers/assets.rb
    
    # Be sure to restart your server when you modify this file.
    # Version of your assets, change this if you want to expire all your assets.
    Rails.application.config.assets.version = '1.0'
    
    # Add additional assets to the asset load path
    # Rails.application.config.assets.paths << Emoji.images_path
    
    # Precompile additional assets.
    # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
    # Rails.application.config.assets.precompile += %w( search.js )
    config/production.rb
    
      # Do not fallback to assets pipeline if a precompiled asset is missed.
      config.assets.compile = false
    

    我已尝试在链接帖子中发布的每个解决方案(主要来自在此主板上发布的其他人。我很想学习解决这个问题的原则(这样我就可以开始学习思考了) rails希望我这样做的方式。我感到困惑的是为什么这么困难,以及为什么在任何文本中编写应用程序以便在生产中工作的原因很少。显然有一个问题需要解决方案(我已经梳理了关于这个主题的100多个其他帖子,但找不到原则性的答案)或有效的解决方案。

    如果它有任何区别,我的生产环境是在heroku上。对于相关原则的任何建议都将非常感激 - 如果直接答案不是立即显而易见的话。

    采取R_G&#39; S建议

    我更改了我的address.js文件,以包含新的第一行和新的最后一行。那个文件现在有:

    ;(function ready() {
    function initMap() {
      var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 5
      });
      var bounds = new google.maps.LatLngBounds();
      // var opts = {
      //   zoom: 10,
      //   max_zoom: 16
      // }
    
      var n = addresses.length;
      for (var i = 0; i < n; i++) {
        var lat = addresses[i].latitude;
        var lng = addresses[i].longitude;
        if (lat == null || lng ==null){
          console.log(addresses[i].name + " doesn't have coordinates");
        }else {
          var address = new google.maps.Marker({
            position: {lat: parseFloat(lat), lng: parseFloat(lng)},
            title: addresses[i].name,
            map: map //,
    //        zoom: 8
          });
          bounds.extend(address.position);
        }
      }
      map.fitBounds(bounds);
    }
    })();
    

    当我启动服务器并尝试渲染页面时,地图仍然不会渲染(只是一个空的空白区域)。 Chrome检查器中没有显示控制台错误(正如我不使用R_G建议的第一行和最后一行时那样)。

    响应工程师DAVE 回答你的问题:

    Q1:您的生产资产是否已预先编译?

    不 - 原因是我的production.rb笔记告诉我不要。见这里:

    # Do not fallback to assets pipeline if a precompiled asset is missed.
      config.assets.compile = true
    
      # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
    

    我理解这些注释意味着assets.rb处理预编译,因此不再需要预编译生产资产。我上面复制的第一行说明告诉我不要回退到资产管道,所以我不确定你期望看到的不同。

    在asset.rb中,笔记说:

    # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.# Do not fallback to assets pipeline if a precompiled asset is missed.
    

    我理解这意味着已经处理了application.js中列出的所有内容,因此无需进一步重新编译步骤。我理解(多年来以前尝试解决这个问题,加倍编译是导致一系列单独问题的原因)。

    我的address.js文件列在我的application.js文件中(通过require树),所以它应该由assets.rb使用的任何进程处理。

    Q2。您是否需要application.js

    中的树

    是。我是。

    您的评论:&#34;此外,如果您不需要application.js中的整个JS文件树,那么您已标记为在assets.rb中进行预编译的文件,例如: address.js将被预编译,但不会被加载。&#34;

    我的application.js有:

    //= require jquery
    //= require jquery_ujs
    //= require turbolinks
    //= require jquery-fileupload/vendor/jquery.ui.widget
    //= require jquery-fileupload/jquery.iframe-transport
    //= require jquery-fileupload/jquery.fileupload
    //= require bootstrap-sprockets
    //= require moment
    //= require bootstrap-datetimepicker
    //= require pickers
    // require underscore
    // require gmaps/google
    //= require markerclusterer
    //= require cocoon
    //= require cable
    //= require_tree .
    

    我要求树。 Address.js位于我的app / assets / javascripts文件夹中,因此它应该被application.js中列表末尾的require_tree行选中。

    我不确定我是否理解你的任何评论。有没有建议我可以尝试让这个工作?您是否建议忽略assets.rb和production.rb设置中的说明?

    &#39;预编译&#39;有什么区别?并且&#39;加载&#39;?我会尝试做一些研究,以了解这意味着什么。

    工程师对R_G&#39; S建议的评论

    EngineerDave建议将this post称为潜在解决方案。这篇文章建议:

    1. 将javascript include标记移动到我的身体标记的末尾(我已经完成了这一操作,其效果是google地图不再有效,但隐藏/显示js在另一个文件中不是&t; t现在工作确实有效。)

    2. 使用此行:

      document.addEventListener(&#34; DOMContentLoaded&#34;,function(event){   //做工作 });

    3. 该帖子继续建议更简单地实现该行,如:

        

      如果有人在这里实际工作的普通javascript实现   想要他们可以插入的代码:   stackoverflow.com/questions/9899372 / ... - jfriend00 12月13日&14; 14日7:58

      That link,建议:

      <script>
      // self executing function here
      (function() {
         // your page initialization code here
         // the DOM will be available here
      
      })();
      </script>
      

      我在address.js中的当前代码以此行开头:

      function initMap() {
      

      根据这篇文章中的建议,我尝试用以下内容替换该行:

      (function() {
        function initMap() {
         //then continue with the rest of my address.js file
      })();
      

      当我保存并尝试时,我会得到与我尝试R_G的第一个建议时相同的结果。没有地图。 Chrome检查器中没有显示控制台错误。

      THE DOWNVOTE

      我不明白对这个问题进行投票的原因。多年来我一直在努力学习如何使用javascript来使用rails。我花了数千美元在codementor.io/ upwork和其他一些网站试图支付专业帮助来学习这个。我有幸参加过我所在城市的每次聚会,并在有机会的时候在不同的城市试一试。我还没找到一个能够解决这个问题的人。 4年多了,我还在努力解决这个问题。投票的理由是什么?它没有给我任何见解,为什么这个论坛不适合寻求帮助。我没有选择替代方案。我只是没有更多的预算浪费在codementor.io上。向下投票只花费我的积分,这使得我能够在这个论坛上开始另一个赏金,以试图找到一些有助于解决这个问题的信息。如果您对如何更好地提出这个问题或进行必要的研究以找到答案有建设性的反馈 - 这些事情中的任何一个都将非常感激。祝你有愉快的一天。

      对其他人,谢谢你试图帮助我。

      BRENZY&S的建议

      非常感谢您抽出宝贵的时间来制作回购。看到其他人说出来这很有帮助。也就是说,这对我不起作用。我不得不调整你的一些方法来摆脱这些给我带来的错误。我已经说明了如何将您的建议和错误汇总到下面:

      Application.html.erb

      的变化:

      1. 我将javascript include标记移回了head标记

      2. 在js include标签上方,我放了谷歌源链接。我已经在下面的评论中显示了您建议的链接,以及我在其下方使用的链接。我不得不更改链接,因为我收到错误,说使用链接没有API密钥。

        <%= csrf_meta_tags %>
        <%= favicon_link_tag %>
        <!-- <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script> -->
        <script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV["GOOGLE_MAPS_API_KEY"] %>"async defer></script>
        
        <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <!-- Latest compiled and minified CSS -->
        <%= stylesheet_link_tag  href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" %>
        
        <!-- Optional theme -->
        <%= stylesheet_link_tag href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap-theme.min.css" %>
        <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
        

      3. 应用/资产/ Javascript角/ initialise.js

        我制作了一个新文件 - 就像你的一样。

        function initialize() {
          var losAngeles = new google.maps.LatLng(34.0500, -118.2500);
          var pasadena = new google.maps.LatLng(34.14778, -118.14452);
          var mapOptions = {
            zoom: 10,
            center: losAngeles,
            disableDefaultUI: true,
            mapTypeControlOptions: google.maps.MapTypeId.SATELLITE
          };
          map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
        }
        
        google.maps.event.addDomListener(window, 'load', initialize);
        

        当前错误指向此文件的最后一行。

        我从您的评论中无法理解的一件事是您认为此文件位于资产管道之外。我不明白,因为你的application.js有require_tree,我理解这意味着app / assets / javascripts中的所有内容都包含在管道中。

        我的观点与你的观点相同:

        <div id="map-canvas"></div>
        

        当我保存所有这些并尝试时,我收到一条错误消息:

        Uncaught ReferenceError: google is not defined
            at initialize.self-f919dc6….js?body=1:13
        (anonymous) @ initialize.self-f919dc6….js?body=1:13
        

        只有一个空白空格而不是地图。

        更大的问题

        我把它推到了heroku并尝试了生产版本。现在,隐藏&amp;显示基于其他表单选择的表单字段不起作用。这是导致将javascript include标记放在正文末尾而不是head标记的原始问题。

        该js位于名为app / assets / javascripts / stance / commercial.js的文件中

        jQuery(document).ready(function() {
           jQuery('[name="organisation[commercial_attributes][standard_financial_split]"]').on('click', function() {
              if (jQuery(this).val() == 'true' ) {
                  jQuery('#commercial_standard_financial_split_content').removeClass('hidden');
              } else {
                  jQuery('#commercial_standard_financial_split_content').removeClass('hidden').addClass('hidden');
              }
           });
        
        });
        

        当javascript包含标记移动到body标记的末尾时,这确实有效。现在它回到了头标记 - 它不起作用。

2 个答案:

答案 0 :(得分:2)

编辑:请参阅最后的更新以获得更详细的说明,但我刚看到您最有可能的错误。如果您遵循我的建议,它肯定会有所帮助。我假设您只粘贴了代码的一个函数,而不是整个文件。在JavaScript中(通常)重要的是确保在代码开始运行之前加载整个页面。这就是我推荐的“function(){...}”的目的。在脚本执行开始之前,它会一直等到文档加载完毕。如果没有它,您可能会在脚本中看到虚假错误,例如“initMap不是函数”。按照我的建议,看看是否有帮助。

你可能已经这样做了,所以请告诉我这是否属实......

如果您的结果因脚本中的位置而异,我的想法是您正在污染全局命名空间并因此遇到冲突的变量。包装所有代码使得它的结构是本地的并且不会影响全局代码更安全。

纯JavaScript会有这种模式:

;(function() {
    // Document is ready here
})();

我使用jQuery,所以我这样做:

;$(function ($, window, document) {
    // Document ready here
}(window.jQuery, window, document));

您希望如何做到这一点取决于您自己的模式,但目标是不污染全球环境。

嘿,这至少值得一试。

更新:既然你问我并向我推荐了第一个建议,那么让我为你解析一下。要使用的代码是:

;(function() {
    // Document is ready here
})();

使用您当前的代码替换“// Document ready ready”。如果您有多个包含当前代码的文件,请对每个文件执行相同操作。

第一个分号就是终止任何前面的代码,以防它们忘记终止它。分号后的括号是本地隔离的关键。它与最后一行的第一个括号配对。您在这些括号内定义的任何变量或函数都将与它们之外的任何内容隔离。最后一行的最后两个成对括号将所有代码作为函数执行,因此实例化内部代码。没有它,您的代码将无法访问。

答案 1 :(得分:1)

我在https://github.com/brenzy/sample1创建了一个非常简单的Rails 5应用程序,可以在开发环境和生产环境中加载谷歌地图。

1)我在资产管道之外添加了google地图脚本,并确保它位于application.js之上:

<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>

2)根据EngineerDave,我使用以下行来确保地图在加载之前不会被初始化。

google.maps.event.addDomListener(window, 'load', initialize);

我没有触及任何默认配置设置。

希望这与您所追求的一致,您可以将其与您的代码进行比较。