Ruby on Rails
Använda GoogleMaps med rails
Sök…
Lägg till Google Maps-javascript-taggen i layouthuvudet
Lägg till javascript-taggen direkt i layouthuvudet i stället för att inkludera den i en vy för att google maps ska fungera korrekt med turbolinks .
# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
%head
- # ...
= google_maps_api_script_tag
google_maps_api_script_tag
definieras bäst i en hjälpare.
# 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
Du kan registrera din ansökan på google och få din api-nyckel i google api-konsolen . Google har en kort guide för att begära en api-nyckel för Google Maps javascript api .
Api-nyckeln lagras i filen secrets.yml
:
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
Glöm inte att lägga till config/secrets.yml
i din .gitignore
fil och se till att du inte begår api-nyckeln till förvaret.
Geocode modellen
Anta att dina användare och / eller grupper har profiler och du vill visa adressprofilfält på en Google-karta.
# 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
Geocoder-pärlan är ett bra sätt att geokodera adresserna, dvs ge longitude
och latitude
.
Lägg till geocoder i din Gemfile
och kör bundle
att installera den.
# Gemfile
gem 'geocoder', '~> 1.3'
Lägg till databaskolumner för latitude
och longitude
för att spara platsen i databasen. Detta är mer effektivt än att fråga efter geokodningstjänsten varje gång du behöver platsen. Det är snabbare och du träffar inte frågegränsen så snabbt.
➜ 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
Lägg till geokodningsmekanismen till din modell. I det här exemplet lagras value
värdeattributet. Konfigurera geokodningen för att utföra när posten har ändrats, och endast när ett värde är närvarande:
# 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
Som standard använder geocoder Google som uppslagstjänst. Det har många intressanta funktioner som avståndsberäkningar eller närhetssökning. För mer information, titta på geocodern README .
Visa adresser på en Google-karta i profilvyn
Visa profilfälten för en användare eller grupp i en lista samt adressfält på en Google-karta.
- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
= render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }
De lämpliga @profile_fields
och @address_fields
ställs in i regulatorn:
# 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
Initiera kartan, placera markörerna, ställ in zoom och andra kartinställningar med javascript.
Ställ markörerna på kartan med javascript
Antag finns en .google_map
div, som kommer att bli kartan och som har adressfälten för att visa som markörer som data
attribut.
Till exempel:
<!-- 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>
För att använda $(document).ready
med turbolinks utan att hantera turbolinkshändelserna för hand, använd jquery.turbolinks-pärla .
Om du vill utföra andra operationer med kartan senare, till exempel filtrering eller infofönster, är det bekvämt att kartan hanteras av en kaffeskriptklass .
# 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
Vid användning av flera kaffe skriptfiler, som namnområde som standard, är det lämpligt att definiera en global App
namespace, som delas av alla kaffe skriptfiler.
Gå sedan igenom (eventuellt flera) .google_map
divs och skapa en instans av klassen App.GoogleMap
för var och en av dem.
# 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
Initiera kartan med en kaffeskriptklass.
Förutsatt en App.GoogleMap
kaffe script klass kan google map initieras så här:
# 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
}
För att lära dig mer om de möjliga alternativen för map_configuration
, titta på Googles MapOptions-dokumentation och deras guide för att lägga till kontrollelement .
Som referens dokumenteras klassen google.maps.Map
här i stort .
Initiera kartmarkörerna med en kaffeskriptklass
Förutsatt en App.GoogleMap
kaffe script klass och markören informationen lagras i data-address-fields
attribut .google_map
div kan kartmarkörer initieras på kartan så här:
# 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
För att lära dig mer om marköralternativ, ta en titt på Googles dokumentation om MarkerOptions och deras guide till markörer .
Zooma automatiskt en karta med en kaffeskriptklass
Förutsatt en App.GoogleMap
kaffe script klass med google.maps.Map
lagras som @map
och google.maps.Marker
s lagras som @markers
, kartan kan vara automatiskt zoomas, det vill säga justerat att alla markörer är synliga, så här : på kartan så här:
# 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
För att lära dig mer om gränser, titta på Googles LatLngBounds-dokumentation .
Att exponera modellegenskaperna som json
För att visa adressprofilfält som markörer på en Google-karta måste adressfältobjekten skickas som json-objekt till javascript.
Vanliga databasattribut
När du ringer to_json
på ett ApplicationRecord
objekt exponeras databasattributen automatiskt.
Med tanke på en ProfileFields::Address
med label
, value
, longitude
och latitude
resulterar address_field.as_json
i en Hash
, t.ex. representation,
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
som konverteras till en json-sträng av to_json
:
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
Detta är användbart eftersom det gör det möjligt att använda label
och value
senare i javascript, till exempel för att visa verktygstips för kartmarkörerna.
Andra attribut
Andra virtuella attribut kan exponeras genom att åsidosätta metoden as_json
.
Till exempel, för att exponera en title
attribut inkludera den i det sammanslagna 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
Exemplet ovan använder super
att kalla den ursprungliga as_json
metoden, som returnerar objektets ursprungliga attribut hash och sammanfogar det med den önskade position hash.
För att förstå skillnaden mellan as_json
och to_json
, titta på detta blogginlägg av jjulian .
Placera
För att göra markörer kräver Google Maps api som standard en position
som har longitud och latitud lagrad som lng
respektive lat
.
Denna position hash kan skapas i javascript, senare eller här när du definierar json-representationen av adressfältet:
För att tillhandahålla denna position
som json-attribut för adressfältet, åsidosätter du bara as_json
metoden på modellen.
# 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