Ruby on Rails
GoogleMapsとRailsの使用
サーチ…
レイアウトヘッダーにGoogleマップのjavascriptタグを追加する
Googleマップをターボリンクで正しく動作させるには、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に登録し、 GoogleのAPIコンソールにあなたのAPIキーを取得することができます。 Googleには、Googleマップのjavascript API用のAPIキーをリクエストする方法についての短いガイドがあります 。
apiキーはsecrets.yml
ファイルに格納されてsecrets.yml
ます:
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
.gitignore
ファイルにconfig/secrets.yml
を追加することを忘れないでください。リポジトリに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
デフォルトでは、ジオコーダーはlookupサービスとして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で設定する
.google_map
divがあり、マップになり、 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の宝石を 。
後で、たとえばフィルタリングや情報ウィンドウなど、マップで他の操作を実行する場合は、 コーヒースクリプトクラスでマップを管理すると便利です。
# 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
ループし、それぞれのApp.GoogleMap
クラスのインスタンスを1つ作成します。
# 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
オプションの詳細については、googleのMapOptionsドキュメントとコントロール要素の追加 に関する ガイドを ご覧 ください 。
参考までに、 ここではgoogle.maps.Map
クラスについて詳しく説明しています 。
コーヒースクリプトクラスを使用して地図マーカーを初期化する
App.GoogleMap
コーヒースクリプトクラスとマーカー情報が.google_map
divのdata-address-fields
属性に格納されているdata-address-fields
、マップマーカーは次のようにマップ上で初期化できます。
# 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
コーヒースクリプトクラスとgoogle.maps.Map
として記憶@map
とgoogle.maps.Marker
Sとして記憶@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に渡す必要があります。
通常のデータベース属性
ApplicationRecord
オブジェクトに対してto_json
を呼び出すと、データベースの属性が自動的に公開されます。
label
、 value
、 longitude
、およびlatitude
属性を持つProfileFields::Address
モデルが与えられたvalue
、 address_field.as_json
はHash
(例:表現)をaddress_field.as_json
、
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
to_json
によってjson文字列に変換されます。
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
これは、後でjavascriptでlabel
とvalue
を使用できるようにするために便利です(たとえば、マップマーカーのツールヒントを表示するなど)。
その他の属性
他の仮想属性は、 as_json
メソッドをオーバーライドすることで公開できます。
たとえば、 title
属性を公開するには、マージされた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
とto_json
違いを理解するには、 as_json
ブログ記事をご覧ください 。
ポジション
マーカーをレンダリングするには、デフォルトでgoogle maps apiに、経度と緯度がそれぞれlng
とlat
として格納されたposition
ハッシュが必要です。
この位置ハッシュは、アドレスフィールドのjson表現を定義するときに、javascript、later、またはここで作成できます。
このposition
をアドレスフィールドのjson属性としてas_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