Ruby on Rails
GoogleMaps mit Rails verwenden
Suche…
Fügen Sie den Javascript-Tag von Google Maps zum Layout-Header hinzu
Damit Google Maps ordnungsgemäß mit Turbolinks funktioniert, fügen Sie das Javascript-Tag direkt zum Layout-Header hinzu, anstatt es in eine Ansicht aufzunehmen.
# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
%head
- # ...
= google_maps_api_script_tag
Der google_maps_api_script_tag
sich am besten in einem Helfer definieren.
# 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
Sie können Ihre Anwendung bei Google registrieren und Ihren API-Schlüssel in der Google API-Konsole abrufen . Google hat eine kurze Anleitung, wie Sie einen API-Schlüssel für die Google Maps-JavaScript-API anfordern .
Der API-Schlüssel wird in der Datei secrets.yml
gespeichert:
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
Vergessen Sie nicht, config/secrets.yml
zu Ihrer .gitignore
Datei .gitignore
und sicherzustellen, dass Sie den API-Schlüssel nicht in das Repository einbinden.
Geokodieren Sie das Modell
Angenommen, Ihre Benutzer und / oder Gruppen verfügen über Profile, und Sie möchten Adressprofilfelder auf einer Google-Map anzeigen.
# 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
Eine gute Möglichkeit, die Adressen zu geokodieren, dh longitude
und latitude
anzugeben, ist der Geocoder-Edelstein .
Fügen Sie Geocoder zu Ihrem Gemfile
und führen Sie ein bundle
, um es zu installieren.
# Gemfile
gem 'geocoder', '~> 1.3'
Fügen Sie Datenbankspalten für latitude
und longitude
, um den Standort in der Datenbank zu speichern. Dies ist effizienter, als den Geokodierungsdienst jedes Mal abzufragen, wenn Sie den Standort benötigen. Es ist schneller und Sie erreichen das Abfragelimit nicht so schnell.
➜ 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
Fügen Sie Ihrem Modell den Geokodierungsmechanismus hinzu. In diesem Beispiel wird die Adresszeichenfolge im value
Attribut gespeichert. Konfigurieren Sie die Geokodierung so, dass sie ausgeführt wird, wenn sich der Datensatz geändert hat und nur ein Wert vorhanden ist:
# 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
Geocoder verwendet standardmäßig Google als Suchdienst. Es hat viele interessante Features wie Entfernungsberechnungen oder Annäherungssuche. Weitere Informationen finden Sie in der README des Geocoders .
Zeigen Sie Adressen auf einer Google-Karte in der Profilansicht an
Zeigen Sie in der Profilansicht die Profilfelder eines Benutzers oder einer Gruppe in einer Liste sowie die Adressfelder in einer Google-Map an.
- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
= render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }
Die entsprechenden @profile_fields
und @address_fields
werden im Controller festgelegt:
# 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
Initialisieren Sie die Karte, setzen Sie die Markierungen, stellen Sie den Zoom und andere Karteneinstellungen mit Javascript ein.
Setzen Sie die Markierungen auf der Karte mit Javascript
Nehmen wir an , es gibt eine .google_map
div, die die Karte mit sich, und die hat die Adressfelder als Marker zu zeigen , data
Zum Beispiel:
<!-- 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>
Um das $(document).ready
mit Turbolinks zu nutzen, ohne die Turbolinks-Ereignisse von Hand zu verwalten, verwenden Sie den Edelstein jquery.turbolinks .
Wenn Sie später noch andere Vorgänge mit der Karte ausführen möchten, z. B. Filter- oder Infofenster, ist es sinnvoll, die Karte von einer Kaffeeskriptklasse verwalten zu lassen.
# 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
Wenn Sie mehrere Kaffeeskriptdateien verwenden, die standardmäßig einen Namensraum haben, ist es zweckmäßig, einen globalen App
Namensraum zu definieren, der von allen Kaffeeskriptdateien gemeinsam genutzt wird.
Dann durchlaufen Sie (möglicherweise mehrere) .google_map
und erstellen App.GoogleMap
für jede einzelne eine Instanz der App.GoogleMap
Klasse.
# 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
Initialisieren Sie die Karte mit einer Kaffeeskriptklasse.
Eine bereitgestellt App.GoogleMap
Kaffee Script - Klasse kann die Google - Karte wie folgt initialisiert werden:
# 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
}
Weitere map_configuration
zu den möglichen Optionen für map_configuration finden Sie in der Google MapOptions-Dokumentation und in deren Anleitung zum Hinzufügen von Steuerelementen .
Als Referenz ist die Klasse google.maps.Map
hier ausführlich dokumentiert .
Initialisieren Sie die Kartenmarkierungen mithilfe einer Kaffeeskriptklasse
GEWäHR App.GoogleMap
Kaffee Skript - data-address-fields
.google_map
Klasse und die Markierungsinformation in dem gespeichert werden data-address-fields
Attribut des .google_map
div können die Kartenmarkierungen auf der Karte wie folgt initialisiert werden:
# 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
Weitere Informationen zu Markierungsoptionen finden Sie in der Google MarkerOptions-Dokumentation und in deren Leitfaden zu Markern .
Auto-Zoom einer Karte mit einer Kaffeeskriptklasse
Eine bereitgestellt App.GoogleMap
Kaffee Skript - google.maps.Map
@map
google.maps.Marker
@markers
Klasse mit dem google.maps.Map
als gespeicherte @map
und die google.maps.Marker
s als gespeicherte @markers
, die Karte kann automatisch gezoomt, dh eingestellt sein , dass alle Markierungen sichtbar sind, wie dies : auf der Karte wie folgt:
# 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
Weitere Informationen zu Grenzen finden Sie in der LatLngBounds-Dokumentation von Google .
Darstellen der Modelleigenschaften als Json
Um Adressprofilfelder als Markierungen auf einer Google-Map anzuzeigen, müssen die Adressfeldobjekte als Json-Objekte an Javascript übergeben werden.
Regelmäßige Datenbankattribute
Beim Aufruf von to_json
für ein ApplicationRecord
Objekt werden die Datenbankattribute automatisch to_json
.
Wenn ein ProfileFields::Address
Modell mit Attributen für label
, value
, longitude
und latitude
, führt address_field.as_json
zu einem Hash
, z.
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
welches von to_json
in einen json-String to_json
:
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
Dies ist nützlich, da Sie später in Javascript label
und value
, um beispielsweise Tooltipps für die Kartenmarkierungen anzuzeigen.
Andere Attribute
Andere virtuelle Attribute können durch Überschreiben der as_json
Methode as_json
werden.
Um beispielsweise ein title
Attribut as_json
zu machen, as_json
es in den zusammengeführten as_json
Hash ein:
# 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
Das obige Beispiel verwendet super
, um die ursprüngliche as_json
Methode as_json
, die den ursprünglichen Attributhash des Objekts zurückgibt und ihn mit dem erforderlichen Positionshash zusammenführt.
Um den Unterschied zwischen as_json
und to_json
zu verstehen, as_json
to_json
einen Blick auf diesen Blogbeitrag von jjulian .
Position
Um Marker zu rendern, erfordert die Google Maps-API standardmäßig einen position
der Längen- und Breitengrad als lng
bzw. lat
.
Dieser Positionshash kann in Javascript erstellt werden, später oder hier, wenn Sie die Json-Darstellung des Adressfelds definieren:
Um diese position
als json-Attribut des Adressfelds as_json
, überschreiben as_json
einfach die as_json
Methode im Modell.
# 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