4

I have been trying for years to figure out how to incorporate gmaps4rails in a rails app.

I have made an entirely new app and tried fresh.

I can't figure out what's going wrong. I'm looking for setup instructions that are complete and up to date. Many SO posts refer to old versions of dependencies that end up saying that the issue is solved in a later version.

Currently, I have this in my view:

<script src="//maps.google.com/maps/api/js?v=3.23&key=<%= ENV['GOOGLE_MAPS_API_KEY'] %>"></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js" type="text/javascript"></script>

<div style='width: 800px;'>
  <div id="map" style='width: 800px; height: 400px;'></div>
</div>

<script type="text/javascript">
  handler = Gmaps.build('Google');
  handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
    markers = handler.addMarkers(<%=raw @hash.to_json %>);
    handler.bounds.extendWith(markers);
    handler.fitMapToBounds();
  });
</script>

In my application.js, I have:

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require moment
//= require bootstrap-datetimepicker
//= require pickers
//= require underscore
//= require gmaps/google
//= require markerclusterer
//= require_tree .

I have saved the production version of underscore.js in my vendor/assets/javascripts folder. I also saved markerclusterer.js as a file in the same folder.

In my gem file, I have:

gem 'geocoder'
gem 'gmaps4rails', '~> 2.1', '>= 2.1.2'
gem 'countries'
gem 'country_select'

In my controller, I have:

class AddressesController < ApplicationController

    def index
    end

    def show
        @hash = Gmaps4rails.build_markers(@address) do |address, marker|
          marker.lat address.latitude
          marker.lng address.longitude
       end
    end

    def new
        @address = Address.new
    end 

    def create
    @address = Address.new(address_params)
    # authorize @address

    respond_to do |format|
      if @address.save
        format.html { redirect_to @address, notice: 'Address was successfully created.' }
        format.json { render :show, status: :created, location: @address }
      else
        format.html { render :new }
        format.json { render json: @address.errors, status: :unprocessable_entity }
      end
    end
  end


  private
    # Use callbacks to share common setup or constraints between actions.
    def set_address
      @address = Address.find(params[:id])
      # authorize @address
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def address_params
      params[:address].permit(:unit, :building, :street_number, :street, :city, :region, :zip, :country, :time_zone, :latitude, :longitude)
    end


    def user_time_zone(&block)
      Time.use_zone(current_user.time_zone, &block)
    end
end

When I try to render the view with the map, the chrome inspector shows errors as:

v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js Failed to load resource: the server responded with a status of 404 (Not Found) chrome-extension://mkjojgglmmcghgaiknnpgjgldgaocjfd/content/contentScripts/kwift.CHROME.min.js:1271 Uncaught SyntaxError: Identifier 'findGoodContent' has already been declared util.js:221 Google Maps API warning: NoApiKeys https://developers.google.com/maps/documentation/javascript/error-messages#no-api-keys util.js:221 Google Maps API warning: RetiredVersion https://developers.google.com/maps/documentation/javascript/error-messages#retired-version util.js:221 Google Maps API warning: InvalidKey https://developers.google.com/maps/documentation/javascript/error-messages#invalid-key

I don't understand any of these errors and I can't find instructions for how to setup this gem to use it in rails. I can see that it has been downloaded a lot - people must have figured out how to set it up. I am sending myself crazy trying to figure this out.

AFTER REGENERATING API KEY

I tried regenerating my browser API key on the google console.

Now when I try to render the page, I get these console errors:

primitives.self-5b8a3a6….js?body=1:5 Uncaught ReferenceError: google is not defined(…)Gmaps.Google.Primitives @ primitives.self-5b8a3a6….js?body=1:5Gmaps.Objects.Handler.Handler.setPrimitives @ handler.self-2f220ca….js?body=1:122Handler @ handler.self-2f220ca….js?body=1:8build @ base.self-8dd1d1a….js?body=1:9(anonymous function) @ VM2063:2t.SnapshotRenderer.n.assignNewBody @ turbolinks.self-c5acd7a….js?body=1:6t.SnapshotRenderer.n.replaceBody @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6t.Renderer.t.renderView @ turbolinks.self-c5acd7a….js?body=1:6t.SnapshotRenderer.n.render @ turbolinks.self-c5acd7a….js?body=1:6t.Renderer.t.render @ turbolinks.self-c5acd7a….js?body=1:6t.View.e.renderSnapshot @ turbolinks.self-c5acd7a….js?body=1:6t.View.e.render @ turbolinks.self-c5acd7a….js?body=1:6t.Controller.r.render @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6
turbolinks.self-c5acd7a….js?body=1:6 GET http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js t.SnapshotRenderer.n.assignNewBody @ turbolinks.self-c5acd7a….js?body=1:6t.SnapshotRenderer.n.replaceBody @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6t.Renderer.t.renderView @ turbolinks.self-c5acd7a….js?body=1:6t.SnapshotRenderer.n.render @ turbolinks.self-c5acd7a….js?body=1:6t.Renderer.t.render @ turbolinks.self-c5acd7a….js?body=1:6t.View.e.renderSnapshot @ turbolinks.self-c5acd7a….js?body=1:6t.View.e.render @ turbolinks.self-c5acd7a….js?body=1:6t.Controller.r.render @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6
turbolinks.self-c5acd7a….js?body=1:6 GET http://localhost:3000/users/assets/images/grayscale.svg t.SnapshotRenderer.n.assignNewBody @ turbolinks.self-c5acd7a….js?body=1:6t.SnapshotRenderer.n.replaceBody @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6t.Renderer.t.renderView @ turbolinks.self-c5acd7a….js?body=1:6t.SnapshotRenderer.n.render @ turbolinks.self-c5acd7a….js?body=1:6t.Renderer.t.render @ turbolinks.self-c5acd7a….js?body=1:6t.View.e.renderSnapshot @ turbolinks.self-c5acd7a….js?body=1:6t.View.e.render @ turbolinks.self-c5acd7a….js?body=1:6t.Controller.r.render @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6(anonymous function) @ turbolinks.self-c5acd7a….js?body=1:6
util.js:221 Google Maps API warning: NoApiKeys https://developers.google.com/maps/documentation/javascript/error-messages#no-api-keysuD.S @ util.js:221(anonymous function) @ js?v=3.23&key=:127(anonymous function) @ js?v=3.23&key=:47(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:47(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97jc @ js?v=3.23&key=:46gc.Qc @ js?v=3.23&key=:97(anonymous function) @ common.js:1
util.js:221 Google Maps API warning: RetiredVersion https://developers.google.com/maps/documentation/javascript/error-messages#retired-versionuD.S @ util.js:221(anonymous function) @ js?v=3.23&key=:127(anonymous function) @ js?v=3.23&key=:47(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:47(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97jc @ js?v=3.23&key=:46gc.Qc @ js?v=3.23&key=:97(anonymous function) @ common.js:1
util.js:221 Google Maps API warning: InvalidKey https://developers.google.com/maps/documentation/javascript/error-messages#invalid-keyuD.S @ util.js:221(anonymous function) @ js?v=3.23&key=:127(anonymous function) @ js?v=3.23&key=:47(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:47(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97(anonymous function) @ js?v=3.23&key=:44(anonymous function) @ js?v=3.23&key=:97jc @ js?v=3.23&key=:46gc.Qc @ js?v=3.23&key=:97(anonymous function) @ common.js:1

I can also see when I look in the terminal for rails s:

ActionController::RoutingError (No route matches [GET] "/assets/underscore-min.map"):

Parameters: {"id"=>"4"}
ActionController::RoutingError (No route matches [GET] "/users/assets/images/grayscale.svg"):

In relation to the underscore routing error, the line in the terminal refers to assets/underscore. My file structure is vendor/assets/javascripts and then the file is saved as underscore.js (not min.map).

ANOTHER ATTEMPT

I tried replacing the js v3.23 with v3.24 and that got rid of the above warning messages. However, I still can't get a a map to render an address. When I inspect the chrome console inspector, I can see that the address is acknowledged in the javascript, but the latitude and longitude details are not:

  handler = Gmaps.build('Google');
  handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
    markers = handler.addMarkers([{"lat":null,"lng":null,"infowindow":"Unit 1\u003cbr\u003e34 Darling Street\u003cbr\u003eBuilding D\u003cbr\u003eBalmain East   NSW   2041\u003cbr\u003eAustralia"}]);
    handler.bounds.extendWith(markers);
    handler.fitMapToBounds();
  });

I'm now wondering if this problem might have something to do with the model associations.

I have an address model and an organisation model. The associations are:

Address:

belongs_to :addressable, :polymorphic => true, optional: true

Organisation:

has_many :addresses, as: :addressable
    accepts_nested_attributes_for :addresses,  reject_if: :all_blank, allow_destroy: true

In my address controller show action, I have:

def show
        @hash = Gmaps4rails.build_markers(@address) do |address, marker|
          marker.lat user.latitude
          marker.lng user.longitude
          # marker.title user.title
      end
    end

In my organisation controller show action, I have:

    def show
    @addresses = @organisation.addresses

    @hash = Gmaps4rails.build_markers(@addresses) do |address, marker|
        marker.lat address.latitude
        marker.lng address.longitude
        marker.infowindow address.full_address
    end    
  end

The partial with the map in it is in views/addresses/map.html.erb

When I try to render the page again with these changes, I get a lot of errors that all say:

js?v=3.24&key=AIzaSyAleQgfNH3HRQVUCYnyAzp46xmXW7WrWrc:37 Uncaught RangeError: Maximum call stack size exceeded

I've read other SO posts where people have had this error and the notes go on to discuss 'recursive loops'. I don't seem to have any code which is similar to the code shown in those errors, so I'm not sure how to address these messages.

I'm wondering if I need to change the organisation controller action to somehow reference the organisation address instead of addresses generally (although if that's the case, then I don't understand how the console inspector shows the correct address being identified in the js from the map partial).

Can anyone help with a detailed step by step tutorial that I could use in trying to figure this out?

Others with similar problems

I can see from other SO posts that others have had similar problems. The advice seems to be this answer: Gmaps4rails Maximum call stack size exceeded?

I think I've already done this though - my show action in each of the address controller and organisation controller both refer to lat/lng rather than the full words (which are used in the db).

ERIC'S SUGGESTION

Taking Eric's suggestion, I removed gmaps4rails gem from the gem file, and the require/gmaps line from application.js

I changed the show action of my organisations controller to:

def show
    @addresses = @organisation.addresses.all

    # @hash = Gmaps4rails.build_markers(@addresses) do |address, marker|
    #     marker.lat address.latitude
    #     marker.lng address.longitude
    #     marker.infowindow address.full_address
    # end

  end

This step is the same as Eric's suggestion for the index action of his markers controller. I separately have an addresses controller which has an index action similar to Eric's. In my db, addresses are polymorphic and belong to organisations. I'm trying to render the map on the organisations show page, so I think this step is consistent with Eric's suggestion.

Next I updated my addresses/_map.html.erb with:

<h3>My Google Maps Demo</h3>
<div id="map"></div>

<%= javascript_tag do %>
  var addresses = <%= raw @addresses.to_json %>;
<% end %>

<script async defer
src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAPS_API_KEY'] %>&callback=initMap">
</script>

I made a new file in my app/javascripts folder for addresses.js, with:

   function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 4
  });
  var bounds = new google.maps.LatLngBounds();

  var n = addresses.length;
  for (var i = 0; i < n; i++) {
    var address = new google.maps.Address({
      position: {lat: parseFloat(addresses[i].latitude), lng: parseFloat(addresses[i].longitude)},
      title: addresses[i].name,
      map: map
    });
    bounds.extend(address.position);
  }

  map.fitBounds(bounds);
}

When I save all this and try it, an empty grey box appears on the screen.

When I use the chrome inspector I can see:

//<![CDATA[

  var addresses = [{"id":5,"unit":"1","building":"d","street_number":"34","street":"darling street","city":"Balmain East","region":"NSW","zip":"2041","country":"AU","time_zone":"International Date Line West","addressable_id":1,"addressable_type":"Organisation","description":"main_address","created_at":"2016-10-27T19:17:27.919Z","updated_at":"2016-11-08T22:48:16.978Z","latitude":"-33.85751","longitude":"151.193546"}];

//]]>

The above is the address in the db. But it isn't making a map.

Can anyone see what I need to do to get the map to render with the address?

WHEN I LOOK AT THE CHROME CONSOLE INSPECTOR

I can see several new errors in the console inspector.

They are:

addresses.self-176b72f….js?body=1:9 Uncaught TypeError: google.maps.Address is not a constructor

This post has a similar problem. The accepted solution is to add a callback. I don't know how or where to do that.

Google Maps API v3 - TypeError: Result of expression 'google.maps.LatLng' [undefined] is not a constructor

Community
  • 1
  • 1
Mel
  • 2,481
  • 26
  • 113
  • 273
  • I couldn't find any instruction for gmaps4rails and Rails 5. Do you just want to display markers on a map, or do you need something else? I've had good experiences with Open Layers 3 : https://openlayers.org/. It's javascript only, so it should work with any Rails version. – Eric Duminil Nov 04 '16 at 12:16
  • Not sure about how well the gem works, but it's not necessary to use it. See google's [map javascript](https://developers.google.com/maps/documentation/javascript/adding-a-google-map) guide. – max pleaner Nov 05 '16 at 17:47
  • @maxpleaner - do you know where to find resources to help understand how to use the map javascript guide in rails. I am trying, but not getting anywhere on my own. I don't mind trying without the gmaps4rails gem - but I'm not clever enough to understand how to get this working without help. I can't believe that I've now been trying for 4+ years and this is too difficult for me to comprehend. – Mel Nov 06 '16 at 23:16
  • Go to that link. It shows a little html and Javascript snippet. Put that in your code. You should be able to see a map. – max pleaner Nov 06 '16 at 23:17
  • I tried it Max. I'm struggling to plug it in so that I can use addresses from my db in the code. – Mel Nov 06 '16 at 23:27
  • Just remove this from your html and add inside application.html.erb your issue will solve – Darpan Chhatravala Nov 08 '16 at 06:40
  • For integrate google map you does not need to use gmap4rails you can do it without gem. and your map performance will quit batter. with jquery – Darpan Chhatravala Nov 08 '16 at 06:41
  • None of these suggestions have worked. Thanks anyway for giving this post your attention. I'll keep searching for a solution that I can establish. I must be the only person that can't figure out how to include maps. – Mel Nov 09 '16 at 22:41

3 Answers3

2

For a start try to get rid from "NoApiKeys", "InvalidKey" errors. Have you generated key like its written in this instruction? Are you sure that you put generated key into ENV['GOOGLE_MAPS_API_KEY'] ?

sig
  • 267
  • 1
  • 10
  • I have. The api keys are orange warnings not red errors. I followed the setup instructions to get those keys so I don't know why it isn't working. Where do you suggest I look for alternative instructions to generating keys that do not present organge warning issues when you try to use them. I followed the instructions on google/maps in my admin console. – Mel Oct 25 '16 at 20:16
  • Either way, I just regenerated the key to check. Now, when I try, I get an additional error. Current console errors are posted above in the update. – Mel Oct 25 '16 at 21:46
  • Is your key the same string as `ENV['GOOGLE_MAPS_API_KEY']` in your app? – sig Oct 26 '16 at 09:44
  • i mean `ENV['GOOGLE_MAPS_API_KEY'] == 'your_generated_api_key'` equals `true` ? – sig Oct 26 '16 at 09:45
  • thanks anyway for trying to help me. I haven't managed to find a way to set up google maps in my app yet. I'll keep trying. I suppose its unrealistic to think a 4 year effort might come to an outcome as quickly as the presidential election. Thanks anyway. – Mel Nov 09 '16 at 22:43
1

Here is the smallest Rails app I could get running with Google Maps.

Ruby 2.3.1, Rails 5.0.0.1, no extra gem needed.

rails new gmaps

uncomment

gem 'therubyracer', platforms: :ruby

in Gemfile

bundle install

rails generate resource marker name:string latitude:decimal longitude:decimal

rake db:migrate

app/controllers/markers_controller.rb:

class MarkersController < ApplicationController
  def index
    @markers = Marker.all
  end
end

app/views/markers/index.html.erb:

<h3>My Google Maps Demo</h3>
<div id="map"></div>

<%= javascript_tag do %>
  var markers = <%= raw @markers.to_json %>;
<% end %>

<script async defer
src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAPS_API_KEY'] %>&callback=initMap">
</script>

app/assets/stylesheets/markers.scss:

#map {
  height: 400px;
  width: 100%;
}

app/assets/javascripts/markers.js:

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 4
  });
  var bounds = new google.maps.LatLngBounds();

  var n = markers.length;
  for (var i = 0; i < n; i++) {
    var marker = new google.maps.Marker({
      position: {lat: parseFloat(markers[i].latitude), lng: parseFloat(markers[i].longitude)},
      title: markers[i].name,
      map: map
    });
    bounds.extend(marker.position);
  }

  map.fitBounds(bounds);
}

Add some Markers in rails c :

Marker.create(:name => 'Sydney', :latitude => -33.87, :longitude => 151.17)
Marker.create(:name => 'Uluru', :latitude => -25.363, :longitude => 131.044)

Add your API KEY to the environment in bash :

export GOOGLE_MAPS_API_KEY="AIza.............................."

rails s

Done!

I used this answer and this Gmaps documentation.

You probably should check that no malicious code is transmitted to javascript, e.g. via Marker#name.

Community
  • 1
  • 1
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • Hi Eric, I tried this. It didn't work. I have updated my post to show the process I went through and the output I get from this attempt. Thanks anyway for trying to help me. – Mel Nov 08 '16 at 22:50
  • Did you try to generate a new Rails app, like I mentioned? If it works, you should then slowly add more and more parts from your existing app. It's pretty hard to debug javascript google maps, because if something doesn't work (model, view, javascript, css), you don't see anything. That's why I find it easier to start simple. – Eric Duminil Nov 08 '16 at 22:55
  • I will try a whole new app next. This is the 4th new app i have tried to make already. I'm not confident that a 5th will bring about another outcome, but ill give it a try. – Mel Nov 08 '16 at 23:06
  • I found console errors in the chrome inspector that come from this attempt. I'm research how to solve those errors now. Can you make sense of the error messages? – Mel Nov 08 '16 at 23:28
  • thanks anyway for trying to help me. This didn't work. I'll keep trying. Im 4 years and 2 months into trying. I suppose it would be a shame to give up now. – Mel Nov 09 '16 at 22:42
  • Please try with a `google.maps.Marker`. I couldn't find `google.maps.Address` in https://developers.google.com/maps/documentation/javascript/3.exp/reference Also, don't forget to add the css – Eric Duminil Nov 09 '16 at 22:57
  • How do i add the css? I changed all instances of marker to address because that was the name of my model (compared to yours which was marker) – Mel Nov 09 '16 at 22:58
  • 1
    WAIT - changing var address = new google.maps.Marker({ has got this rendering a map. I can't believe this is over. THANK YOU!!! – Mel Nov 09 '16 at 22:59
  • This is a Javascript class you're talking about, so it should be called Marker, as Google intended. For the css, see `app/assets/stylesheets/markers.scss` in my post. – Eric Duminil Nov 09 '16 at 23:00
  • Actually - I spoke to soon. This only works if I complete the latitude and longitude fields in the console. My geocode gem isn't working. The attributes in the console for lat/lng return nil and the console errors continue as before: Uncaught RangeError: Maximum call stack size exceeded – Mel Nov 09 '16 at 23:45
  • Please write another question, it's getting hard to follow. – Eric Duminil Nov 10 '16 at 07:43
  • I did. It's here: http://stackoverflow.com/questions/40518141/google-maps-setting-it-up-to-work-with-rails-5-geocoder-not-geocoding – Mel Nov 10 '16 at 10:34
0

Hopefully you have it sorted but is seems like your JS is wrong for your api key. Were you getting an OOPS error? You need to use an updated version with 'v=3' in it.

<script src="//maps.google.com/maps/api/js?v3key=[API_KEY]"></script>
LiffeyD
  • 103
  • 6