【Rails6】ポートフォリオへのGoogleMapの導入

#はじめに

ポートフォリオ作成時によくWebサービスで見る、GoogleMapを導入してみたい！！と思い、実装したので、今回備忘録と復習のため記事を記述します。
内容は、表示ページに遷移すると、現在地の取得の有無が表示され、許可をすると、
現在地を表示することができ、検索フォームで検索したい場所を入力することで、その場所も表示できるような仕様です。

参考にさせていただいた記事は、[【Rails6 / Google Map API】初学者向け！Ruby on Railsで簡単にGoogle Map APIの導入する](https://qiita.com/nagaseToya/items/e49977efb686ed05eadb)
です！本当にありがとうございました。

#環境

Ruby on Rails '6.0.0'
Ruby '2.6.5'

#前提

- Google Cloud PlatformにてAPIキーを取得済み。
※GeocodingAPIとMaps JavaScript APIを選択。
※APIキーの取得方法については今回は割愛します。
- 私のポートフォリオでは、記事(articleテーブル)の詳細ページに表示するものとして記述していきます。

#viewファイルの編集

APIキーを取得することができたら、ほとんどviewファイルの編集で完了しました。。表示させたいhtml.erbに以下の記述をしました。


```ruby:app/views/layouts/_map.html.erb
<div class="search-form">
  <input id="address" class="search-name" type="textbox" placeholder="現在地から近くの役所が検索できます">
  <input type="button" class="btn btn-outline-success" value="検索する" onclick="codeAddress()">
</div>

<div id='map'></div>

<style>
#map {
  height: 50vh;
  width: 60vw;
  margin: 0 auto;
}
</style>

<script>
  let map
  let geocoder

  function initMap(){
    geocoder = new google.maps.Geocoder()
    if(!navigator.geolocation) {
      alert('Geolocation APIに対応していません');
      return false;
    }

    navigator.geolocation.getCurrentPosition(function(position) {
      latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);

      map = new google.maps.Map(document.getElementById('map'), {
        center: latLng,
        zoom: 12,
      });

      marker = new google.maps.Marker({
        position:  latLng,
        map: map
      });
    }, function() {
        alert('位置情報取得に失敗しました');
      });
  }

  function codeAddress(){
    let inputAddress = document.getElementById('address').value;

    geocoder.geocode( { 'address': inputAddress}, function(results, status) {
      if (status == 'OK') {
        map.setCenter(results[0].geometry.location);
        let marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
        });
      } else {
          alert('該当する結果がありませんでした：' + status);
      }
    });   
  }
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_SECRET_KEY'] %>&callback=initMap" async defer></script>
```

では、部分的に分けて解説していきます。

```ruby:app/views/layouts/_map.html.erb
<div class="search-form">
  <input id="address" class="search-name" type="textbox" placeholder="現在地から近くの役所が検索できます">
  <input type="button" class="btn btn-outline-success" value="検索する" onclick="codeAddress()">
</div>
```

上段のこの部分でまず検索フォームを実装しています。ボタンなどはbootstrapを使用しています。

```ruby:app/views/layouts/_map.html.erb
<style>
#map {
  height: 50vh;
  width: 60vw;
  margin: 0 auto;
}
</style>
```

こちらの部分では、地図の大きさや配置を決めています。


```ruby:app/views/layouts/_map.html.erb
#↓現在地の取得処理
function initMap(){
    geocoder = new google.maps.Geocoder()
    if(!navigator.geolocation) {
      alert('Geolocation APIに対応していません');
      return false;
    }
#↑ユーザーの端末がGoogleMapに対応していなければ、地図は表示されないようにしています。
    navigator.geolocation.getCurrentPosition(function(position) {
      latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);

      map = new google.maps.Map(document.getElementById('map'), {
        center: latLng,
        zoom: 12,
      });
#↑位置情報の取得ができれば、latLngに現在地の緯度と軽度の情報が定義され、マップに表示する処理を行なっています。
#「center: latLng」で現在地を地図の中央に表示し、「zoom: 12」は拡大の倍率になっています。

      marker = new google.maps.Marker({
        position:  latLng,
        map: map
      });
#↑現在地にマーカーを表示しています。
    }, function() {
        alert('位置情報取得に失敗しました');
      });
  }
#なんらかの形で取得に失敗した場合、alertで表示するようにしています。
```

上記はページを開いた初期表示の段階です。コメントアウトで処理内容について記述しています。

```ruby:app/views/layouts/_map.html.erb
#検索ボタンをクリックすることで処理が走りだします。
  function codeAddress(){
    let inputAddress = document.getElementById('address').value;
#↑検索フォームに入力された位置を取得しています。
    geocoder.geocode( { 'address': inputAddress}, function(results, status) {
      if (status == 'OK') {
        map.setCenter(results[0].geometry.location);
        let marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
        });
#↑検索結果がヒットしたときに、検索結果の緯度と経度を地図に表示するとともに、マーカーを設置しています。
      } else {
          alert('該当する結果がありませんでした：' + status);
      }
    });   
  }
#↑検索結果が該当なしであれば上記を表示しています。
```

上記は検索結果を表示する際の処理になります。

```ruby:app/views/layouts/_map.html.erb
<script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_SECRET_KEY'] %>&callback=initMap" async defer></script>
```

最後の行で、APIキーの取得を行なっています。
取得したキーは環境変数にて取扱を行なってください。

#おわりに

以上で実装は完了です。表示ページに遷移すると、位置情報の取得について有無が問われるため、許可をすると、現在地が表示されます。
今回は検索を行うと、自分の位置情報と、検索結果の該当する場所の2点にマーカーが刺さるような仕組みになっています。ここから、検索結果までの距離や時間の表示までできれば、なお使いやすいアプリケーションになるかと思いますので、勉強します。
相違点ありましたら、ご指摘ください。