【Rails】Geocoding APIを用いて高精度で緯度経度を算出し、Google Mapに表示する方法

# 目標
**ユーザーが登録した住所をマップの中心に表示し、マーカーを立てる。**
![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/73406c27-1c6e-0b81-179a-d6189f0c9453.gif)

# 開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

# 前提

下記実装済み。

・[Slim導入](https://qiita.com/matsubishi5/items/b639ffddecc626856039)
・[ログイン機能実装](https://qiita.com/matsubishi5/items/5bd8fdd45af955cf137d)
・[Google Map表示](https://qiita.com/matsubishi5/items/196fa1941da2152b6d5d)

`gem 'geocoder'`だけでは精度が低い(番地指定が出来ない地域がある)為、
`Geocoding API`を使用して高精度で住所から緯度経度を特定出来る様に実装していきます。

# `Geocoding API`有効化

### 1.下記リンクにアクセス

[Google Cloud Platform](https://console.cloud.google.com/home/dashboard?project=clear-tooling-279101)

### 2. 「APIの概要に移動」をクリック

![スクリーンショット 2020-06-03 10.01.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/001f6bac-126a-02a5-85dd-e8fa61def834.png)

### 3.「ライブラリ」をクリック

![スクリーンショット 2020-06-03 10.01.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/756331dd-f7fe-c7be-8ef4-a52da30411b4.png)

### 4.検索フォームに「geo」と入力し、「Geocoding API」をクリック

![スクリーンショット 2020-06-03 10.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/4010e36b-8174-2d56-911d-4e0d71dbc3bd.png)

### 5.「有効にする」をクリック

![スクリーンショット 2020-06-03 10.02.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/a2658335-98ea-0fd8-5f8a-226c4f3c7788.png)

### 6.赤枠で囲われている箇所をクリック

![スクリーンショット 2020-06-03 10.02.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/42a40227-e607-1ab5-9bf5-b0153dfb1f7e.png)

### 7.プルダウンメニューが表示されるので、「全てのGoogle Maps API」をクリック

![スクリーンショット 2020-06-03 10.04.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/776101aa-c877-5d43-d7cb-0c4dcb8adda6.png)


### 8.「認証情報」をクリック

![スクリーンショット 2020-06-03 10.12.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/62fa77d9-4c01-622e-8b56-172b8161f30b.png)

### 9.「APIキーの名前」をクリック

![スクリーンショット 2020-06-03 10.12.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/4549e06a-6791-ef6d-de2b-f3e03524fb85.png)

### 10.認証情報の設定をする

**①APIの制限**
`キーを制限`を選択し、プルダウンメニューから`Geocoding API`を選択する。

**②`Maps JavaScript API`と、`Geocoding API`が選択されている事を確認して、`保存`をクリック**

![スクリーンショット 2020-06-03 10.13.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/b1b00df3-9c43-8a81-9fbb-4e242087eaac.png)

### 11.APIが2個になっているかを確認

APIを追加した事でAPIキーが変更されるという事は無いので、これで完了。

![スクリーンショット 2020-06-03 10.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/3769aaac-e746-4f9f-b962-635236285613.png)

# 実装

### 1.Gemを導入

```ruby:Gemfile
gem 'gon'
gem 'geocoder'
```

`gem 'gon'`
➡︎ コントローラーで定義したインスタンス変数をビューのJavaScript内で使用出来る様にする。

`gem 'geocoder'`
➡︎ 住所から緯度経度を算出する。

```terminal:ターミナル
$ bundle
```

### 2.`geocorder`の設定ファイルを作成し、編集

```terminal:ターミナル
$ touch config/initializers/geocoder.rb
```

```ruby:geocoder.rb
# 追記
Geocoder.configure(
  lookup: :google,
  api_key: ENV['GOOGLE_MAP_API']
)
```

これで`Geocoding API`を使用する事ができ、緯度経度の算出が高精度で行えます。


### 3.カラムを追加

```terminal:ターミナル
$ rails g migration AddColumnsToUsers address:string latitude:float longitude:float
```

```ruby:add_columns_to_users.rb
class AddColumnsToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :address, :string
    add_column :users, :latitude, :float
    add_column :users, :longitude, :float
  end
end
```

```terminal:ターミナル
$ rails db:migrate
```

### 4.モデルを編集

```ruby:user.rb
  # 追記
  geocoded_by :address
  after_validation :geocode
```

`geocoded_by :address`
➡︎  addressカラムを基準に緯度経度を算出する。

`after_validation :geocode`
➡︎ 住所変更時に緯度経度も変更する。

### 5.コントローラーを編集

**①`application_controller.rb`を編集**

ストロングパラメーターに「address」を追加します。

```ruby:application_controller.rb
def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :name, :address])
end
```

**②`users_controller.rb`を編集**

```ruby:users_controller.rb
def show
  @user = User.find(params[:id])
  gon.user = @user # 追記
end
```

### 6.ビューを編集

**①`application.html.slim`を編集**

`gon`を読み込みます。
CSSとJavaScriptより先に読み込んでいる事に注意して下さい。

```slim:application.html.slim
doctype html
html
  head
    title
      | Bookers2
    = csrf_meta_tags
    = csp_meta_tag
    = include_gon # 追記
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
```

**②新規会員登録画面に住所入力フォームを追加**

```slim:resistrations/new.html.slim
= f.label :address, '住所'
br
= f.text_field :address, class: 'form-control'
br
```

**③マップを編集**

```slim:users/show.html.erb
#map style='height: 500px; width: 500px;'

- google_api = "https://maps.googleapis.com/maps/api/js?key=#{ ENV['GOOGLE_MAP_API'] }&callback=initMap".html_safe
script{ async src=google_api }

javascript:

  let map;

  function initMap() {
    geocoder = new google.maps.Geocoder()

    map = new google.maps.Map(document.getElementById('map'), {
      // コントローラーで定義した変数から緯度経度を呼び出し、マップの中心に表示
      center: {
        lat: gon.user.latitude,
        lng: gon.user.longitude
      },
      zoom: 12,
    });

    marker = new google.maps.Marker({
      // コントローラーで定義した変数から緯度経度を呼び出し、マーカーを立てる
      position: {
        lat: gon.user.latitude,
        lng: gon.user.longitude
      },
      map: map
    });
  }
```

# 注意

`turbolinks`を無効化しないと地図が切り替わらないので、必ず無効化しておきましょう。

[turbolinksを無効化する方法](https://qiita.com/matsubishi5/items/c4c8a5df03ae630ae534)