サーチ…


レイアウトヘッダーに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

すなわち、住所をジオコード提供するための素晴らしい方法longitudelatitudeあるジオコーダ宝石

Gemfile追加し、 bundleを実行してインストールします。

# Gemfile
gem 'geocoder', '~> 1.3'

latitudelongitudeデータベース列を追加して、データベース内の場所を保存します。これは、場所を必要とするたびにジオコーディングサービスを照会するより効率的です。それは速く、クエリー制限をあまりにも速く打つことはありません。

➜ 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として記憶@mapgoogle.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を呼び出すと、データベースの属性が自動的に公開されます。

labelvaluelongitude 、およびlatitude属性を持つProfileFields::Addressモデルが与えられたvalueaddress_field.as_jsonHash (例:表現)を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でlabelvalueを使用できるようにするために便利です(たとえば、マップマーカーのツールヒントを表示するなど)。

その他の属性

他の仮想属性は、 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_jsonto_json違いを理解するには、 as_json ブログ記事をご覧ください

ポジション

マーカーをレンダリングするには、デフォルトでgoogle maps apiに、経度と緯度がそれぞれlnglatとして格納された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


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow