Ruby on Rails
Использование GoogleMaps с Rails
Поиск…
Добавьте тег javascript Google Maps в заголовок макета
Чтобы карты Google корректно работали с turbolinks , добавьте тег javascript непосредственно в заголовок макета, а не включите его в представление.
# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
%head
- # ...
= google_maps_api_script_tag
Значение google_maps_api_script_tag
лучше всего определено в помощнике.
# 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
Вы можете зарегистрировать свое приложение в Google и получить свой ключ api в консоли google api . В Google есть краткое руководство о том, как запросить ключ api для javascript api .
Ключ api хранится в файле secrets.yml
:
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
Не забудьте добавить config/secrets.yml
в ваш .gitignore
файл и убедитесь, что вы не передаете ключ api в репозиторий.
Геокодировать модель
Предположим, что у ваших пользователей и / или групп есть профили, и вы хотите отображать поля профиля адреса на карте 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
Отличный способ геокодирования адресов, то есть обеспечить longitude
и latitude
- это драгоценный камень геокодирования .
Добавьте геокодер в свой Gemfile
и запустите bundle
чтобы установить его.
# Gemfile
gem 'geocoder', '~> 1.3'
Добавьте столбцы базы данных для latitude
и longitude
, чтобы сохранить местоположение в базе данных. Это более эффективно, чем запрос службы геокодирования каждый раз, когда вам нужно место. Это быстрее, и вы не так быстро достигаете предела запроса.
➜ 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
Добавьте механизм геокодирования к вашей модели. В этом примере строка адреса хранится в атрибуте value
. Настройте геокодирование для выполнения, когда запись изменилась, и только то, что имеет значение:
# 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
По умолчанию геокодер использует google как службу поиска. Он имеет множество интересных функций, таких как дистанционные вычисления или поиск близости. За дополнительной информацией обратитесь к геокодированию README .
Показывать адреса на карте google в профиле
В представлении профиля отобразите поля профиля пользователя или группы в списке, а также поля адреса на карте google.
- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
= render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }
Соответствующие @profile_fields
и @address_fields
задаются в контроллере:
# 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
Инициализируйте карту, поместите маркеры, установите масштаб и другие настройки карты с помощью javascript.
Установите маркеры на карте с помощью javascript
Предположим, что есть div .google_map
, который станет картой и который имеет поля адреса, которые будут отображаться как маркеры как атрибут data
.
Например:
<!-- 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>
Чтобы использовать событие $(document).ready
с turbolinks без управления событиями turbolinks вручную, используйте jquery.turbolinks gem .
Если вы хотите выполнить некоторые другие операции с картой, позже, например, для фильтрации или инфо-окна, удобно иметь карту, управляемую классом сценария кофе .
# 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
При использовании нескольких файлов сценариев кофе, которые по умолчанию являются именами, удобно определять глобальное пространство имен App
, которое используется всеми файлами кофейных скриптов.
Затем .google_map
(возможно, несколько) .google_map
и создайте один экземпляр класса 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
Инициализируйте карту, используя класс сценария кофе.
При условии класса сценария кофе-скрипта App.GoogleMap
карту google можно инициализировать следующим образом:
# 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
}
Чтобы узнать больше о возможных параметрах map_configuration
, просмотрите документацию MapOptions Google и их руководство по добавлению элементов управления .
Для справки, класс google.maps.Map
широко документирован здесь .
Инициализация маркеров карты с использованием класса сценария кофе
При условии, что App.GoogleMap
сценария кофе App.GoogleMap
и информация о маркере, хранящаяся в атрибуте data-address-fields
в div .google_map
, маркеры карт могут быть инициализированы на карте следующим образом:
# 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
Чтобы узнать больше о параметрах маркера, ознакомьтесь с документацией Google MarkerOptions и их руководством к маркерам .
Автоматическое масштабирование карты с использованием класса сценария кофе
При условии, что App.GoogleMap
сценария кофе-класса App.GoogleMap
содержит App.GoogleMap
google.maps.Map
хранящуюся как @map
а @map
google.maps.Marker
хранится как @markers
, карта может быть автоматически увеличена, то есть отрегулирована, чтобы все маркеры были видны, например : на карте:
# 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
Чтобы узнать больше о границах, просмотрите документацию Google LatLngBounds .
Отображение свойств модели как json
Чтобы отображать поля профиля адреса в качестве маркеров на карте google, объекты поля адреса должны передаваться как json-объекты в javascript.
Обычные атрибуты базы данных
При вызове to_json
объекта ApplicationRecord
автоматически отображаются атрибуты базы данных.
Учитывая модель ProfileFields::Address
с атрибутами label
, value
, longitude
и latitude
, address_field.as_json
приводит к Hash
, например, представлению,
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
который преобразуется в строку json to_json
:
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
Это полезно, потому что позволяет использовать label
и value
позже в javascript, например, чтобы показать подсказки инструментов для маркеров карты.
Другие атрибуты
Другие виртуальные атрибуты могут быть раскрыты путем переопределения метода as_json
.
Например, чтобы открыть атрибут title
, as_json
его в объединенный хэш as_json
:
# 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
В приведенном выше примере super
используется для вызова исходного метода as_json
, который возвращает исходный хэш атрибута объекта и объединяет его с требуемым хэш- as_json
позиции.
Чтобы понять разницу между as_json
и to_json
, посмотрите на это сообщение в блоге jjulian .
Позиция
Для рендеринга маркеров google maps api по умолчанию требует хеш position
который имеет долготу и широту, хранящиеся как lng
и lat
соответственно.
Эта позиция hash может быть создана в javascript, позже или здесь при определении json-представления поля адреса:
Чтобы обеспечить эту position
как json-атрибут поля адреса, просто переопределите метод as_json
на модели.
# 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