Rails5でGoogleMapを表示してみるまで

# はじめに
Infratopという会社でプログラミングスクールでメンターをしていま~~す~~した。
~~最近、GoogleMapで地図出したいんだけど上手く出ないという質問がありまして、
この際、まとめ記事を書いてしまおうと思った次第です。~~

# 環境
- ruby 2.5.1
- rails 5.2.1

# すること
- Google MapのAPI Keyを取得
- 地名から緯度経度情報を取得
- 経度緯度情報から地図を表示


それじゃあLet's GO.

# API Keyを取得
予めGoogleアカウントは作っておきましょう。

[Google Map Platform](https://cloud.google.com/maps-platform/)にアクセスしてください。
画像に従ってプロジェクトを生成します。

<img width="1472" alt="スクリーンショット 2018-12-18 14.42.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/577ed2ad-180e-2f88-e65e-1d1bf1c7f3e9.png">
<img width="1472" alt="スクリーンショット 2018-12-18 14.42.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/537320ec-9633-bba9-3089-f42583af5227.png">

次に請求情報を登録します。２通りに分けて、簡単に説明しますが、
**請求アカウントを登録しないと、Google Mapが表示されないので注意してください。**

## 過去にGoogleアカウントの請求情報を登録している場合
過去にGoogle APIを使用し、請求情報を登録していると次のようになり、API Keyを取得できます。
<img width="1472" alt="スクリーンショット 2018-12-18 14.43.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/0c44a556-709d-4407-ebd0-309ccde838f1.png">

<img width="1472" alt="スクリーンショット 2018-12-18 14.43.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/6ab0f119-bace-658f-e40c-b5271b285682.png">

## 新しくGoogleアカウントの請求情報を登録する場合
こちらの記事に詳細が載っています。
この記事はとても丁寧に記述していらっしゃるので、従えば登録できるはずです。
[【2018年7月16日版】Google Maps の APIキー を取得する](https://nendeb.com/276)

余力があったら本記事で同様の内容をいずれ追記しようと思います。

## Maps JavaScript APIの有効化と制限
発行したAPI Keyに対してGoogle MapのAPIを有効化します。

また、セキュリティの関係で、APIを使えるURLを設定します。
ここでは、開発用にlocalhostで使えるようにします。

図に従って、設定をしてください。

<img width="1472" alt="スクリーンショット 2018-12-18 15.23.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/811ef39f-c994-6040-9ba2-961471270225.png">
<img width="1472" alt="スクリーンショット 2018-12-18 15.23.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/74f3526e-bfe5-e15c-3f3a-1afba9d137f4.png">
<img width="1472" alt="スクリーンショット 2018-12-18 15.23.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/3453f405-af42-1349-44cb-7fa235a97443.png">
<img width="1472" alt="スクリーンショット 2018-12-18 15.24.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/78ab0635-97e8-a825-c45d-fa1198ad0c3c.png">
<img width="1472" alt="スクリーンショット 2018-12-18 15.25.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/511dadad-7e58-a23a-581f-7bf6fed9234a.png">
<img width="1472" alt="スクリーンショット 2018-12-18 15.25.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/e07989a3-0c9c-f728-ed0e-3d0154d188ca.png">

とにかく**localhostでアクセス可**にすればOKです。

# APIで地図を表示
適当なアプリケーションを作成し、そこでテストします。

```
rails new gmap-test //rails アプリケーションを作成
rails g controller maps index //mapsコントローラ(とindexアクション)を作成
```

とりあえずルーティング設定

```ruby:routes.rb
Rails.application.routes.draw do
  root to: 'maps#index'
  resources :maps, only: [:index]
end
```

## scriptの記述 
```html:index.html.erb
<h2>gmap</h2>
<div id='map'></div>

<style>
#map{
  height: 400px;
}
</style>

<script>
function initMap(){
  let map = new google.maps.Map(document.getElementById('map'), {
  center: {lat: -34.397, lng: 150.644},
  zoom: 8
  });
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>
```

簡略のため、html内にstyleとscriptを記述しています。
`YOUR_API_KEY`のところを取得したAPIキーに差し替えてください。
`rails s`で実行し、確認すると、次のような画面になります。

<img width="1364" alt="スクリーンショット 2018-12-19 12.08.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/9393630b-f5e4-dcec-2c59-064f2cc23494.png">

# 地名でmapを移動する
Google Map APIは経度緯度情報で移動できるので、
地名や住所を入力したら経度緯度を取得できるようにしましょう。
そういう機能をGeocoding(ジオコーディング)といいます。

ここでは、二つの方法を示します。どちらかでGeocodingしましょう。

- GoogleのGeocoding APIを利用する。
- gemのgeocoderを利用する。

GoogleのAPIを使用するときは、クライアント側で経度緯度情報を取得します。
一方、gemのgeocoderを使用する場合は、サーバ側で経度緯度情報を取得します。

作成するアプリケーションによって、どちらが適しているか判断してください。

## 方法1:Google Geocoding APIを利用する。

まずはGeocoding APIを有効化します。
Maps JavaScript APIを有効化したときと同様に行えばOKです。
簡単に遷移を示しておきます。
`Google Cloud Platformをクリック > APIの概要に移動 > +APIとサービスの有効化　> geocodingで検索`

<img width="1364" alt="スクリーンショット 2018-12-19 12.20.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/eedc31ac-2024-dbc8-e544-0b4881c74422.png">

htmlとscriptを以下のように変更します。

```html:index.html.erb
<h2>gmap</h2>

<!-- 地名入力用のinputを追加 -->
<input id="address" type="textbox" value="Sydney, NSW">

<!-- buttonをクリックしたらcodeAddressを実行　-->
<input type="button" value="Encode" onclick="codeAddress()">
<div id='map'>
</div>

<style>
#map{
  height: 400px;
}
</style>

<script>
/*
mapを関数の外で定義(codeAddressでも使うため)
geocoderを用意
*/

let map
let geocoder

function initMap(){
  // geocoderを初期化
  geocoder = new google.maps.Geocoder()

  map = new google.maps.Map(document.getElementById('map'), {
  center: {lat: -34.397, lng: 150.644},
  zoom: 8
  });
}

function codeAddress(){
  // 入力を取得
  let inputAddress = document.getElementById('address').value;

  // geocodingしたあとmapを移動
  geocoder.geocode( { 'address': inputAddress}, function(results, status) {
    if (status == 'OK') {
　　　　　　　　　　　　// map.setCenterで地図が移動
      map.setCenter(results[0].geometry.location);

　　　　　　　　　　　　// google.maps.MarkerでGoogleMap上の指定位置にマーカが立つ
      var marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
      });
    } else {
      alert('Geocode was not successful for the following reason: ' + status);
    }
  });
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script>
```
これで完了です。
適当に東京と入力して、ボタンを押せば地図が切り替わります。
<img width="1364" alt="スクリーンショット 2018-12-19 12.33.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/2c3e6c1e-0540-25b6-1550-77a6c8c3f065.png">


## 方法2:gemのgeocoderを利用する
方法１と同様にinputに入力したら地図が変わるようにしたいので、
Ajaxを用いて非同期に対応させます。(formをremote: trueで送るだけです)
Ajaxについてはこちらの、「[RailsでAjax基本形（Scaffoldで学ぶ）](https://qiita.com/mm36/items/684f36f22e79d0a27ae9)」がわかりやすいです。

まずはGemfileにgeocoderを記述して、`bundle install`をします。
また、Mapsコントローラにmapアクションを追加し、それに対応したルーティングを設定します。

```text:Gemfile
gem 'geocoder'
```

```ruby:maps_controller.rb
def index
end
:
:
def map
  # respond_to以下の記述によって、
  # remote: trueのアクセスに対して、
  # map.js.erbが変えるようになります。
  respond_to do |format|
    format.js
  end
end
```

```ruby:routes.rb
：
get '/map_request', to: 'maps#map', as: 'map_request'
：
```
--- 

次に`views/maps`の下に、map.js.erbを作成します。
画像のようにindex.html.erbと並列になっていればOKです。
<img width="352" alt="スクリーンショット 2018-12-19 15.02.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/563639ce-c0ed-c7a6-0145-983b97609597.png">

とりあえず、map.js.erbにconsole.logでも書いておきましょう

```erb:map.js.erb
console.log('hoge')
```

---

次にformを作成します。
同時にgoogleの初期化も記述してしまいましょう。

```erb:index.html.erb
<h2>gmap</h2>
<!-- form_withはデフォルトでremote: trueの挙動になります -->
<%= form_with url: map_request_path, method: :get do |f|%>
  <%= f.text_field :address %>
  <%= f.submit '地図表示' %>
<% end %>

<div id="map">
</div>

<style>
#map{
  height: 400px;
}
</style>

<script>
  let mapInstance //この変数はmap.js.erbでも使うのでタイプミスに注意

  function initMap(){
    mapInstance = new google.maps.Map(document.getElementById('map'), {
    center: {lat: -34.397, lng: 150.644},
    zoom: 8
    });
  }
</script>
<script src="https://maps.googleapis.com/maps/api&/js?key=YOUR_API_KEY&callback=initMap" async defer></script>

```

ここまで記述して、ボタンを押せば、
consoleに'hoge'と出るはずです。

<img width="1364" alt="スクリーンショット 2018-12-19 15.10.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/d8ef8c40-b487-fc16-f92a-441dd6ee0eb9.png">

---
それではgeocoderで経度緯度情報を取得します。

```ruby:map_controller.rb

def map
  results = Geocoder.search(params[:address])
  @latlng = results.first.coordinates
  # これでmap.js.erbで、経度緯度情報が入った@latlngを使える。

  respond_to do |format|
    format.js
  end
end
```

map.js.erbで地図の移動とマーカの記述をします。

```js:map.js.erb
/* 
index.html.erbのscript内に
google mapのインスタンス変数である、
mapという変数があることに留意
*/

(function(){
  // 位置情報をもつ変数を用意
  let pos = new google.maps.LatLng(
   <%= @latlng[0] %>, //latitude
   <%= @latlng[1] %>  //longitude
  );

  mapInstance.setCenter(pos)
  let marker = new google.maps.Marker({
    map: mapInstance,
    position: pos
  });
})()
```

これでGoogle GeocodingAPIと同等の処理が完成しました。
GemのGeocoderを使う場合、Railsのコントローラを挟むので、
データベースで何かしたい場合はこちらのほうが楽だと思います。
<img width="1364" alt="スクリーンショット 2018-12-19 15.45.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/131386/467f06fa-c786-27cb-3485-93413d448513.png">

##おわりに
以上になります。
GoogleMapにはまだまだたくさんの機能があります。
公式ドキュメントのリンクを貼っておくので参照してみてください。
[Google Maps Platform](https://developers.google.com/maps/documentation/?hl=ja)