Ruby on Rails
Korzystanie z GoogleMaps z Railsami
Szukaj…
Dodaj tag javascript Google Maps do nagłówka układu
Aby mapy Google działały poprawnie z turbolinkami , dodaj tag javascript bezpośrednio do nagłówka układu, zamiast umieszczać go w widoku.
# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
%head
- # ...
= google_maps_api_script_tag
google_maps_api_script_tag
najlepiej zdefiniować w pomocniku.
# 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
Możesz zarejestrować swoją aplikację w Google i uzyskać klucz API w konsoli Google API . Google ma krótki przewodnik, jak poprosić o klucz API dla Google Maps Java API .
Klucz API jest przechowywany w pliku secrets.yml
:
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
Nie zapomnij dodać config/secrets.yml
do .gitignore
pliku i makre pewno nie popełnić klucz API do repozytorium.
Geokoduj model
Załóżmy, że twoi użytkownicy i / lub grupy mają profile i chcesz wyświetlić pola profilu adresu na mapie Google.
# 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
Świetnym sposobem na geokodowanie adresów, tj. Podanie longitude
i latitude
jest klejnot geokodera .
Dodaj Gemfile
do Gemfile
i uruchom bundle
aby go zainstalować.
# Gemfile
gem 'geocoder', '~> 1.3'
Dodaj kolumny bazy danych dla latitude
i longitude
, aby zapisać lokalizację w bazie danych. Jest to bardziej wydajne niż odpytywanie usługi geokodowania za każdym razem, gdy potrzebujesz lokalizacji. Jest szybszy i nie wyczerpujesz tak szybko limitu zapytań.
➜ 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
Dodaj mechanizm geokodowania do swojego modelu. W tym przykładzie ciąg adresu jest przechowywany w atrybucie value
. Skonfiguruj geokodowanie, aby działało, gdy rekord się zmieni, i tylko wtedy, gdy wartość jest obecna:
# 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
Domyślnie geocoder używa Google jako usługi wyszukiwania. Ma wiele interesujących funkcji, takich jak obliczanie odległości lub wyszukiwanie bliskości. Aby uzyskać więcej informacji, zapoznaj się z geokoderem README .
Pokaż adresy na mapie Google w widoku profilu
W widoku profilu pokaż pola profilu użytkownika lub grupy na liście, a także pola adresu na mapie Google.
- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
= render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }
Odpowiednie @profile_fields
i @address_fields
są ustawione w kontrolerze:
# 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
Zainicjuj mapę, umieść znaczniki, ustaw powiększenie i inne ustawienia mapy za pomocą javascript.
Ustaw znaczniki na mapie za pomocą javascript
Załóżmy, że istnieje div .google_map
, która stanie się mapą i która będzie miała pola adresu, które będą wyświetlane jako znaczniki jako atrybut data
.
Na przykład:
<!-- 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>
Aby skorzystać ze zdarzenia $(document).ready
z turbolinkami bez ręcznego zarządzania zdarzeniami turbolinks, użyj klejnotu jquery.turbolinks .
Jeśli chcesz wykonać inne operacje na mapie, później, na przykład filtrowanie lub okna informacyjne, wygodnie jest zarządzać mapą za pomocą klasy skryptu kawowego .
# 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
Podczas korzystania z kilku plików skryptów kawy, które są domyślnie z przestrzenią nazw, wygodnie jest zdefiniować globalną przestrzeń nazw App
, która jest współdzielona przez wszystkie pliki skryptów kawy.
Następnie .google_map
przez (ewentualnie kilka) .google_map
div .google_map
i utwórz dla każdej z nich jedną instancję klasy 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
Zainicjuj mapę za pomocą klasy skryptu kawowego.
Pod warunkiem App.GoogleMap
kawy App.GoogleMap
mapę Google można zainicjować w następujący sposób:
# 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
}
Aby dowiedzieć się więcej o możliwych opcjach map_configuration
, zapoznaj się z dokumentacją MapOptions Google i ich przewodnikiem po dodawaniu elementów sterujących .
Dla porównania klasa google.maps.Map
jest tutaj obszernie udokumentowana .
Zainicjuj znaczniki mapy za pomocą klasy skryptu kawy
Pod warunkiem, że App.GoogleMap
skryptu kawy App.GoogleMap
i informacje o znaczniku są przechowywane w atrybucie data-address-fields
div .google_map
, znaczniki mapy można zainicjować na mapie w następujący sposób:
# 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
Aby dowiedzieć się więcej o opcjach znaczników, zapoznaj się z dokumentacją MarkerOptions firmy Google i ich przewodnikiem po znacznikach .
Automatyczne powiększanie mapy za pomocą klasy skryptu kawowego
Pod warunkiem, że App.GoogleMap
skryptów do kawy google.maps.Map
przechowywana jako @map
jako @map
i google.maps.Marker
jako @markers
, mapa może być automatycznie powiększana, tzn. Dostosowywana tak, aby wszystkie markery były widoczne, tak jak to : na mapie w ten sposób:
# 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
Aby dowiedzieć się więcej na temat granic, zapoznaj się z dokumentacją Google LatLngBounds .
Ujawnianie właściwości modelu jako json
Aby wyświetlić pola profilu adresu jako znaczniki na mapie Google, obiekty pola adresu należy przekazać jako obiekty JSON do javascript.
Regularne atrybuty bazy danych
Podczas wywoływania funkcji to_json
na obiekcie ApplicationRecord
atrybuty bazy danych są automatycznie ujawniane.
Biorąc pod uwagę ProfileFields::Address
Model ProfileFields::Address
z atrybutami label
, value
, longitude
i latitude
, pole address_field.as_json
powoduje Hash
, np. Reprezentację,
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
który jest konwertowany na ciąg json przez to_json
:
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
Jest to przydatne, ponieważ pozwala na użycie label
i value
później w javascript, na przykład w celu wyświetlenia podpowiedzi do znaczników mapy.
Inne atrybuty
Inne atrybuty wirtualne można wyświetlić, zastępując metodę as_json
.
Na przykład, aby odsłonić atrybut title
, as_json
go do scalonego 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
W powyższym przykładzie użyto super
do wywołania oryginalnej metody as_json
, która zwraca oryginalny skrót wartości obiektu i łączy go z wymaganym as_json
pozycji.
Aby zrozumieć różnicę między as_json
i to_json
, spójrz na ten post na blogu autorstwa jjulian .
Pozycja
Aby renderować znaczniki, interfejs Google Maps domyślnie wymaga skrótu position
który ma długość i szerokość geograficzną przechowywane odpowiednio jako lng
i lat
.
Ten skrót pozycji można utworzyć w javascript, później lub tutaj podczas definiowania reprezentacji json pola adresu:
Aby podać tę position
jako atrybut json pola adresu, po prostu zastąp metodę as_json
w modelu.
# 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