Ruby on Rails
GoogleMaps gebruiken met rails
Zoeken…
Voeg de javascript-tag van Google maps toe aan de layoutkop
Om Google Maps goed te laten werken met turbolinks , voegt u de JavaScript-tag rechtstreeks toe aan de lay- outkop in plaats van deze op te nemen in een weergave.
# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
%head
- # ...
= google_maps_api_script_tag
De google_maps_api_script_tag kan het beste in een helper worden gedefinieerd.
# app/helpers/google_maps_helper.rb
module GoogleMapsHelper
def google_maps_api_script_tag
javascript_include_tag google_maps_api_source
end
def google_maps_api_source
"https://maps.googleapis.com/maps/api/js?key=#{google_maps_api_key}"
end
def google_maps_api_key
Rails.application.secrets.google_maps_api_key
end
end
U kunt uw toepassing registreren bij Google en uw API-sleutel ophalen in de Google API-console . Google heeft een korte handleiding voor het aanvragen van een API-sleutel voor de JavaScript-API van Google Maps .
De api-sleutel wordt opgeslagen in het bestand secrets.yml :
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
Vergeet niet om config/secrets.yml .gitignore toe te voegen aan uw .gitignore bestand en zorg ervoor dat u de api-sleutel niet in de repository vastlegt.
Geocode het model
Stel dat uw gebruikers en / of groepen profielen hebben en dat u adresprofielvelden op een google map wilt weergeven.
# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
# Attributes:
# label, e.g. "Work address"
# value, e.g. "Willy-Brandt-Straße 1\n10557 Berlin"
end
Een geweldige manier om de adressen te geocoderen, dwz longitude en latitude is de geocoder-parel .
Voeg geocoder toe aan uw Gemfile en voer de bundle uit om deze te installeren.
# Gemfile
gem 'geocoder', '~> 1.3'
Voeg databasekolommen voor latitude en longitude toe om de locatie in de database op te slaan. Dit is efficiënter dan elke keer dat u de locatie nodig hebt, vragen naar de geocoderingsservice. Het is sneller en u bereikt de vraaglimiet niet zo snel.
➜ bin/rails generate migration add_latitude_and_longitude_to_profile_fields \
latitude:float longitude:float
➜ bin/rails db:migrate # Rails 5, or:
➜ rake db:migrate # Rails 3, 4
Voeg het geocodeermechanisme toe aan uw model. In dit voorbeeld wordt de adresstring opgeslagen in het value . Configureer de geocodering om uit te voeren wanneer het record is gewijzigd en alleen wanneer een waarde aanwezig is:
# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
geocoded_by :value
after_validation :geocode, if: ->(address_field){
address_field.value.present? and address_field.value_changed?
}
end
Standaard gebruikt geocoder Google als opzoekservice. Het heeft veel interessante functies zoals afstandsberekeningen of nabijheid zoeken. Kijk voor meer informatie op de geocoder README .
Toon adressen op een google map in de profielweergave
Geef in de profielweergave de profielvelden van een gebruiker of groep in een lijst weer, evenals de adresvelden op een google map.
- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
= render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }
De juiste @profile_fields en @address_fields worden ingesteld in de controller:
# app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
def show
# ...
@profile_fields = @user_or_group.profile_fields
@address_fields = @profile_fields.where(type: 'ProfileFields::Address')
end
end
Initialiseer de kaart, plaats de markeringen, stel de zoom en andere kaartinstellingen in met javascript.
Plaats de markeringen op de kaart met JavaScript
Stel dat er een .google_map div is, die de kaart wordt en die de adresvelden heeft om als markeringen als data worden weergegeven.
Bijvoorbeeld:
<!-- http://localhost:3000/profiles/123 -->
<div class="google_map" data-address-fields="[
{label: 'Work address', value: 'Willy-Brandt-Straße 1\n10557 Berlin',
position: {lng: ..., lat: ...}},
...
]"></div>
Gebruik de jquery.turbolinks-edelsteen om gebruik te maken van het $(document).ready evenement met turbolinks zonder de turbolinks-gebeurtenissen handmatig te beheren.
Als u later nog andere bewerkingen met de kaart wilt uitvoeren, bijvoorbeeld filteren of informatievensters, is het handig om de kaart te laten beheren door een koffiescriptklasse .
# app/assets/javascripts/google_maps.js.coffee
window.App = {} unless App?
class App.GoogleMap
constructor: (map_div)->
# TODO: initialize the map
# TODO: set the markers
Wanneer u meerdere koffie-scriptbestanden gebruikt, die standaard een naamruimte hebben, is het handig om een algemene App naamruimte te definiëren die wordt gedeeld door alle koffie-scriptbestanden.
Loop vervolgens (mogelijk meerdere) .google_map divs door en maak voor elk een exemplaar van de klasse App.GoogleMap .
# app/assets/javascripts/google_maps.js.coffee
# ...
$(document).ready ->
App.google_maps = []
$('.google_map').each ->
map_div = $(this)
map = new App.GoogleMap map_div
App.google_maps.push map
Initialiseer de kaart met een koffiescriptklasse.
Mits een App.GoogleMap koffie- App.GoogleMap , kan de google map als volgt worden geïnitialiseerd:
# app/assets/javascripts/google_maps.js.coffee
# ...
class App.GoogleMap
map_div: {}
map: {}
constructor: (map_div)->
@map_div = map_div
@init_map()
@reference_the_map_as_data_attribute
# To access the GoogleMap object or the map object itself
# later via the DOM, for example
#
# $('.google_map').data('GoogleMap')
#
# store references as data attribute of the map_div.
#
reference_the_map_as_data_attribute: ->
@map_div.data 'GoogleMap', this
@map_div.data 'map', @map
init_map: ->
@map = new google.maps.Map(@dom_element, @map_configuration) if google?
# `@map_div` is the jquery object. But google maps needs
# the real DOM element.
#
dom_element: ->
@map_div.get(0)
map_configuration: -> {
scrollWheel: true
}
Voor meer informatie over de mogelijk te leren map_configuration opties, eens een kijkje op google MapOptions documentatie en hun gids voor het toevoegen van bedieningselementen .
Ter referentie wordt de klasse google.maps.Map hier uitgebreid gedocumenteerd .
Initialiseer de kaartmarkeringen met behulp van een koffiescriptklasse
Op voorwaarde dat een App.GoogleMap koffie- App.GoogleMap en de markeringsinformatie wordt opgeslagen in het kenmerk data-address-fields van de .google_map div, kunnen de .google_map als volgt op de kaart worden geïnitialiseerd:
# app/assets/javascripts/google_maps.js.coffee
# ...
class App.GoogleMap
# ...
markers: []
constructor: (map_div)->
# ...
@init_markers()
address_fields: ->
@map_div.data('address-fields')
init_markers: ->
self = this # to reference the instance as `self` when `this` is redefined.
self.markers = []
for address_field in self.address_fields()
marker = new google.maps.Marker {
map: self.map,
position: {
lng: address_field.longitude,
lat: address_field.latitude
},
# # or, if `position` is defined in `ProfileFields::Address#as_json`:
# position: address_field.position,
title: address_field.value
}
self.markers.push marker
Raadpleeg de documentatie van MarkerOptions van Google en hun gids voor markeringen voor meer informatie over opties voor markeringen .
Zoom automatisch op een kaart met een koffiescriptklasse
Mits een App.GoogleMap koffie- App.GoogleMap met de google.maps.Map opgeslagen als @map en de google.maps.Marker opgeslagen als @markers , kan op de kaart automatisch worden ingezoomd, dwz aangepast dat alle markers zichtbaar zijn, zoals deze : op de kaart als volgt:
# app/assets/javascripts/google_maps.js.coffee
# ...
class App.GoogleMap
# ...
bounds: {}
constructor: (map_div)->
# ...
@auto_zoom()
auto_zoom: ->
@init_bounds()
# TODO: Maybe, adjust the zoom to have a maximum or
# minimum zoom level, here.
init_bounds: ->
@bounds = new google.maps.LatLngBounds()
for marker in @markers
@bounds.extend marker.position
@map.fitBounds @bounds
Bekijk de LatLngBounds-documentatie van Google voor meer informatie over grenzen.
De modeleigenschappen blootstellen als json
Om adresprofielvelden weer te geven als markeringen op een google map, moeten de adresveldobjecten als json-objecten worden doorgegeven aan javascript.
Reguliere database-attributen
Wanneer u to_json op een ApplicationRecord object, worden de database-kenmerken automatisch weergegeven.
Gegeven een ProfileFields::Address met kenmerken voor label , value , longitude en latitude , resulteert address_field.as_json in een Hash , bijvoorbeeld representatie,
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
die wordt omgezet in een json-string door to_json :
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
Dit is handig omdat het mogelijk is om label en value later in javascript te gebruiken, bijvoorbeeld om tooltips voor de kaartmarkeringen weer te geven.
Overige attributen
Andere virtuele kenmerken kunnen worden weergegeven door de as_json methode te overschrijven.
Bijvoorbeeld, om een bloot title attribuut, opnemen in het samengevoegde as_json hash:
# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
# ...
# For example: "John Doe, Work address"
def title
"#{self.parent.name}, #{self.label}"
end
def as_json
super.merge {
title: self.title
}
end
end
In het bovenstaande voorbeeld wordt super gebruikt om de oorspronkelijke methode as_json aan te roepen, die de oorspronkelijke attribuuthash van het object retourneert en deze samenvoegt met de vereiste positiehash.
Bekijk het blogbericht van jjulian om het verschil tussen as_json en to_json te begrijpen.
Positie
Om markeringen weer te geven, vereist de API van Google Maps standaard een position hash waarin lengte- en breedtegraad is opgeslagen als respectievelijk lng en lat .
Deze positie-hash kan worden gemaakt in javascript, later of hier bij het definiëren van de json-weergave van het adresveld:
Om deze position als json-kenmerk van het adresveld op te geven, overschrijft u gewoon de as_json methode op het model.
# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
# ...
def as_json
super.merge {
# ...
position: {
lng: self.longitude,
lat: self.latitude
}
}
end
end
