O js de preenchimento automático do Google Maps está funcionando no host local, mas não no heroku

Sou desenvolvedor júnior de ruby on rails. Desenvolvi um aplicativo Web que usa a API javascript do Google Maps e uso a função de preenchimento automático em uma entrada de formulário.

O preenchimento automático funciona bem no host local, mas não funciona mais após a implantação no heroku.

Aqui está o meu html.erb abaixo. Para uma informação perfeita, o formulário está no rodapé da página. Este formulário está parcialmente oculto e a única parte visível corresponde a um botão usado para carregar um arquivo de vídeo. Depois que esse botão foi clicado e o arquivo de vídeo foi escolhido, eu mostro um modal contendo o restante do formulário. É aí que o 'text_field_tag' (com o id = "user_input_autocomplete_address") é exibido e onde o preenchimento automático deve funcionar.

<% if user_signed_in? %>

<div class="footer-check hidden-md hidden-lg">
  <div class="container text-right">
    <div class="row">
      <div class="flexbox">
        <div class="footer-home active">
          <%= link_to root_path do %>
            <i class="fa fa-home" aria-hidden="true"></i>
          <% end %>
        </div>
        <div class="footer-search">
        <!-- later put link_to reviews_path -->
          <%= link_to search_path do %>
            <i class="fa fa-search" aria-hidden="true"></i>
          <% end %>
        </div>
        <div class="footer-button">
        <%= simple_form_for(Review.new) do |f| %>
          <div id="add_video_image_btn">
            <label for="review_video", class="add_video_image"><%= image_tag "plus.png" %></label>
            <%= f.input :video, label: false, input_html: { accept: ".mp4, .mov, .m4v, .wmv, .webm, .avi", class: 'hidden'} %>
            <%= f.input :video_cache, as: :hidden, class: "add_video_image file required" %>
          </div>
        </div>
        <div class="footer-likes">
          <%= link_to dashboard_users_path do %>
            <i class="fa fa-heart" aria-hidden="true"></i>
          <% end %>
        </div>

        <div class="footer-user">
          <%= link_to user_path(current_user) do %>
            <i class="fa fa-user" aria-hidden="true"></i>
          <% end %>
        </div>
      </div>
    </div>
  </div>
</div>

<!--Beginning Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
  <div class="modal-content">
    <div class="modal-body">
      <div id="add_video_form_step2">
        <%= f.error_notification %>

        <fieldset class="form-group" style="margin-bottom:0;">

          <div class="section">
            Place
          </div>
          <div class="inner-wrap">
            <div id="">
              <%= text_field_tag :place, nil, class: 'form-control', id: 'user_input_autocomplete_address', placeholder: 'Start typing...', size: 80 %>
            </div>
          </div>

          <div class="section">
            Comment
          </div>
          <div class="inner-wrap">
            <%= text_field_tag :comment, nil, class:'form-control', placeholder: 'Food is good but the place is a bit noisy', size: 80 %>
          </div>

          <div class="inner-wrap" style="padding:15px;">
            <div class="emoji-toggle emoji-happy">
              <input type="checkbox" id="toggle1" class="toggle" name="review[mood]" value="false">
              <div class="emoji"></div>
              <label for="toggle1" class="well"></label>
            </div>
          </div>

          <div class="">
            <%= f.button :submit, class: "btn btn-primary form-control", id: "click-trigger" %>
          </div>

          <%= hidden_field_tag :name, id: 'name' %>
          <%= hidden_field_tag :street_number, id: 'street_number' %>
          <%= hidden_field_tag :route, id: 'route' %>
          <%= hidden_field_tag :locality, id: 'locality' %>
          <%= hidden_field_tag :administrative_area_level_1, id: 'administrative_area_level_1' %>
          <%= hidden_field_tag :postal_code, id: 'category_0' %>
          <%= hidden_field_tag :country, id: 'country' %>
          <%= hidden_field_tag :formatted_address, id: 'formatted,_address' %>
          <%= hidden_field_tag :phone_number, id: 'phone_number' %>
          <%= hidden_field_tag :website, id: 'website' %>
          <%= hidden_field_tag :gplace_id, id: 'gplace_id' %>
          <%= hidden_field_tag :category_0, id: 'category_0' %>
          <%= hidden_field_tag :category_1, id: 'category_1' %>
          <%= hidden_field_tag :category_2, id: 'category_2' %>
          <%= hidden_field_tag :category_3, id: 'category_3' %>
          <%= hidden_field_tag :category_4, id: 'category_4' %>
          <%= hidden_field_tag :category_5, id: 'category_5' %>
          <%= hidden_field_tag :hours_open_day_0, id: 'hours_open_day_0' %>
          <%= hidden_field_tag :hours_open_day_1, id: 'hours_open_day_1' %>
          <%= hidden_field_tag :hours_open_day_2, id: 'hours_open_day_2' %>
          <%= hidden_field_tag :hours_open_day_3, id: 'hours_open_day_3' %>
          <%= hidden_field_tag :hours_open_day_4, id: 'hours_open_day_4' %>
          <%= hidden_field_tag :hours_open_day_5, id: 'hours_open_day_5' %>
          <%= hidden_field_tag :hours_open_day_6, id: 'hours_open_day_6' %>
        </fieldset>
      </div>
    </div>
    </div>
  </div>
</div>

      </div>
      </div>
    </div>
  </div>
<% end %>
<% end %>

<!--End Modal -->

<!-- Start of js to display the modal -->
<!-- NB: the autocomplete module is in assets/javascript/autocomplete.js -->
<%= content_for :after_js do %>
  <script>
    $('#review_video').change(function(){
      $('#myModal').modal('show');
    });
  </script>
<% end %>
<!-- End of js to display the modal -->

O rodapé (reunindo o modal e o formulário) é chamado na visualização layouts / application.html.erb, abaixo. Você verá que eu uso a chave da API do Google (escondida em application.yml)

<!DOCTYPE html>
<html>
  <head>
    <title><%= meta_title %></title>
    <%= csrf_meta_tags %>

    <!-- Start Favicon -->

    <%= favicon_link_tag '_/app/assets/images/favicon.ico' %>

    <link rel="manifest" href="/manifest.json">
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content="<%= image_path 'ms-icon-144x144.png' %>">
    <meta name="theme-color" content="#ffffff">
    <!-- end Favicon -->

    <meta name="description" content="<%= meta_description %>">

    <!-- Facebook Open Graph data -->
    <meta property="og:title" content="<%= meta_title %>" />
    <meta property="og:type" content="website" />
    <meta property="og:url" content="<%= request.original_url %>" />
    <meta property="og:image" content="<%= meta_image %>" />
    <meta property="og:description" content="<%= meta_description %>" />
    <meta property="og:site_name" content="<%= meta_title %>" />

    <!-- Twitter Card data -->
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="<%= DEFAULT_META["twitter_account"] %>">
    <meta name="twitter:title" content="<%= meta_title %>">
    <meta name="twitter:description" content="<%= meta_description %>">
    <meta name="twitter:creator" content="<%= DEFAULT_META["twitter_account"] %>">
    <meta name="twitter:image:src" content="<%= meta_image %>">

    <!-- Google+ Schema.org markup -->
    <meta itemprop="name" content="<%= meta_title %>">
    <meta itemprop="description" content="<%= meta_description %>">
    <meta itemprop="image" content="<%= meta_image %>">



    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <%= stylesheet_link_tag    'application', media: 'all' %>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <!-- start Mixpanel -->
    <script type="text/javascript">(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
      for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
      mixpanel.init("ENV['MIXPANEL_TOKEN']");
    </script>
    <!-- end Mixpanel -->

  </head>
  <body>
    <%= render 'shared/flashes' %>
    <%= yield %>
    <%= render 'shared/footer' %>
    <%= javascript_include_tag "http://maps.google.com/maps/api/js?libraries=places&key=#{ENV['GMAP_BROWSER_KEY']}" %>
    <%= javascript_include_tag "http://cdn.rawgit.com/mahnunchik/markerclustererplus/master/dist/markerclusterer.min.js" %>
    <%= javascript_include_tag 'application' %>
    <%= yield :after_js %>
  </body>
</html>

Por fim, o código javascript que permite o preenchimento automático na entrada (tendo "id_do_usuário_de_putação_computador" como id) está em assets / javascript / autocomplete.js e é o seguinte:

function initializeAutocomplete(id) {
  var element = document.getElementById(id);
  console.log('coucou');
  if (element) {
    var autocomplete = new google.maps.places.Autocomplete(element, { types: ['geocode', 'establishment'] });
    google.maps.event.addListener(autocomplete, 'place_changed', onPlaceChanged);
  }
}

function onPlaceChanged() {
  var place = this.getPlace();

  console.log(place);  // Uncomment this line to view the full object returned by Google API.

  for (var i in place.address_components) {
    var component = place.address_components[i];
    // console.log(component.types);
    for (var j in component.types) {  // Some types are ["country", "political"]
      var type_element = document.getElementById(component.types[j]); // Returns the div with their differents ids or null if the id doesnt exist
      // console.log(document.getElementById(component.types[j]));
      if (type_element) {
        type_element.value = component.long_name;
      }
    }
  }

  var formatted_address = document.getElementById('formatted_address');
  // console.log(international_phone_number);
  if (formatted_address) {
    formatted_address.value = place.formatted_address;
  }

  for (var i in place.types) {
    // console.log(place.types);
    // console.log(i);
    // console.log(place.types[i]);
    var type_content = document.getElementById('category_' + i); // Returns the div with their differents ids or null if the id doesnt exist
    // console.log(document.getElementById(component.types[j]));
    if (type_content) {
      console.log(place.types[i]);
      type_content.value = place.types[i];
    }
  }

  var international_phone_number = document.getElementById('phone_number');
  // console.log(international_phone_number);
  if (international_phone_number) {
    international_phone_number.value = place.international_phone_number;
  }

  var name = document.getElementById('name');
  if (name) {
    name.value = place.name;
  }

  var gplace_id = document.getElementById('gplace_id');
  if (gplace_id) {
    gplace_id.value = place.place_id;
  }

  var website = document.getElementById('website');
  if (website) {
    website.value = place.website;
  }

  for (var i in place.opening_hours.weekday_text) {
    var hours_open_in_db = place.opening_hours.weekday_text[i];
    var hours_open_in_form = document.getElementById('hours_open_day_' + i);
    if (hours_open_in_form) {
      hours_open_in_form.value = hours_open_in_db;
    }
  }
}

google.maps.event.addDomListener(window, 'load', function() {
  initializeAutocomplete('user_input_autocomplete_address');
});

Para implantar tudo isso no heroku, eu já fiz o seguinte:

"heroku run db: migrate" no terminal (porque eu tinha algumas migrações pendentes);"figaro heroku: set -e production" no terminal, a fim de enviar todas as minhas chaves de API para o heroku (eu também verifiquei se essas chaves estão realmente nos vars de configuração do heroku).no console do desenvolvedor do Google, no meu projeto e na API javascript do mapa do Google, assegurei que minha chave do navegador fosse permitida tanto para o meu locahost quanto para o meu nome de domínio. Para ser mais preciso, estou usando a mesma chave para meu locahost e meu nome de domínio. Até agora, a única coisa que ainda não consegui fazer, no console do Google, é provar que sou o proprietário do meu nome de domínio.Verifiquei que ainda não atingi nenhuma das minhas cotas de API.No meu arquivo autocomplete.js, usei algum console.log para descobrir, no inspetor do meu navegador, quais partes do código estão funcionando. Parece que tudo funciona, exceto os console.logs que estão no retorno de chamada 'OnPlaceChange', pois as sugestões de preenchimento automático do Gmap não são mostradas ...;Eu sei que não ver as sugestões de preenchimento automático não é um problema do z-index associado ao elemento .pac-container css, já que eu já tinha que corrigir isso e já que as sugestões de Gmaps não podem ser alcançadas graças às setas do teclado.Eu li este post sobre geocomplete (geocomplete para trilhos 4 não está funcionando no Heroku) e tentei pré-compilar meus recursos. Isso não levou a nenhuma mudança.No inspetor do navegador (na seção 'rede'), quando escrevo algo no formulário, cada nova letra pressionada no teclado aciona uma nova solicitação. Os nomes dessas solicitações são 'AutocompletionService.GetPredictions .....'. Na seção "cabeçalhos", posso ver que são solicitações https para googleapis, com métodos get e código de status 200. Na seção "resposta", vejo que parece haver um erro nas minhas chaves de API, pois a mensagem é:

/**/_xdc_._ty4oqn && _xdc_._ty4oqn( [3,null,null,"This API project is not authorized to use this API. Please ensure that this API is activated in the APIs Console: https://console.developers.google.com/apis/library?project=_ Please ensure this API is activated in the Google Developers Console: https://console.developers.google.com/apis/api/places_backend?project=_ For more information on authentication and Google Maps Javascript API services please see: https://developers.google.com/maps/documentation/javascript/get-api-key"] )
Segui o link na mensagem de erro, levando-me ao console do Google, e volto às minhas chaves de projeto e API, que são resolvidas no servidor e no navegador. Mais uma vez, a única coisa que não consegui fazer no console do Google foi provar que sou o proprietário do meu nome de domínio.

Esse último ponto é a origem do problema (e, neste caso, acho que preciso de ajuda dos meus serviços de hospedagem) ou vocês vêem outro erro?

questionAnswers(2)

yourAnswerToTheQuestion