【Rails6】Google Map をアプリに埋め込み、入力した住所にマーカーをつける。【細かいところの確認】

簡単に実装できるはずのGoogleMapAPIですが数々の沼にハマったので細かく注意していきます。

# 環境
Rails 6.0.0
Ruby 2.6.5
EC2
Amazon Linux2
Nginx
mariaDB
Capistrano

# 機能
住所を入れると![48b7ab460e405caaf463dd4963cd52af.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696835/e3fad1cb-b526-5fd2-f37c-1ffa2141acd3.png)
DBに住所が保存、緯度経度が自動で算出されて
![f57e6c8b1a108791d56e024334075861.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696835/4eb7b14c-7356-1b79-f19c-7e28f42243b8.png)

表示されます。
![d801305aebecc331b0cfd2a2bb7970d2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696835/171339f7-f693-1ecc-4cb7-4c2b5f2da717.jpeg)
#Google Mapをアプリに埋め込む
<a href="https://cloud.google.com/maps-platform/?hl=ja&utm_source=google&utm_medium=cpc&utm_campaign=FY18-Q2-global-demandgen-paidsearchonnetworkhouseads-cs-maps_contactsal_saf&utm_content=text-ad-none-none-DEV_c-CRE_320617583922-ADGP_Hybrid%20%7C%20AW%20SEM%20%7C%20BKWS%20~%20Google%20Maps%20API%20BMM-KWID_43700039913979172-kwd-313687189577-userloc_1009304&utm_term=KW_%2Bgoogle%20%2Bmap%20%2Bapi-ST_%2Bgoogle%20%2Bmap%20%2Bapi&gclid=CjwKCAjwlbr8BRA0EiwAnt4MThq955XhyzUb7M1GK-21Aiqd5XdDq1JGzLDPjnyvFrBJ-dxCQAyDORoCjAQQAvD_BwE">Google Map API</a>（サービス紹介ページ）

Google Map APIは、GoogleCloudのサービスのひとつで、GoogleCloudPlatformというコンソールから操作します、まずはそこで、Google Map javascript APIのAPIKeyを取得します。

## GoogleCloudPlatformへ
☆Googleのアカウントがなければまずこちらから登録してください。
<a href="https://accounts.google.com/signup/v2/webcreateaccount?hl=ja&flowName=GlifWebSignIn&flowEntry=SignUp">Googleアカウント登録</a>
アカウントを作成したら（持っていたら）コンソールへ
https://console.cloud.google.com/

##プロジェクトを作成し、APIKeyを取得→地図表示
https://qiita.com/nagaseToya/items/e49977efb686ed05eadb
一連の流れはこちらにわかりやすく書かれています。

今回は、ここに加えて任意の住所記録、保存、出力します。

### Geocording
緯度と経度を算出して、特定の位置を見つけてくれる機能です。gemのGeocoderと、Google CloudのGeocodeing APIというサービスを使います。
gemだけでも位置情報を取得することはできますが、「東京駅」では取得できても、「東京都〇〇区〇〇○○ー◯○」という具体的なアドレスでは取得できません。また取得できたりできなかったりします。そのためにより性能の良いGeocodeing APIも使えるようにします。




#コード
モデルは作成されているとします。（例Performancesモデル）
###①マイグレーションファイルを作成(カラム追加)

```
% rails g migration AddColumnsToPerformances
```
・入力された住所addressカラム
・geocodeによって自動で算出される緯度、経度カラム

```
class AddColumnsToPerformances < ActiveRecord::Migration[6.0]
  def change
    add_column :performances, :address, :string
    add_column :performances, :latitude, :float
    add_column :performances, :longitude, :float
  end
end
```
```
% rails db:migrate
```
rollbackでもカラムは変更できますが、データが消えるのでなるべくadd_column（カラム追加）にすると良いと思います！
###②入力フォームの作成
保存先はaddressのみで大丈夫です。

```
<%= form_with(model: @performance, local: true) do |f| %>
***抜粋***
<label for="group-name">住所(GoogleMap表示)</label>
<span class="indispensable-any">任意</span>
<%= f.text_area :address,class:"new-performance-box", id:"gmap", placeholder:"Google Mapの住所をコピーして貼り付けてください" %>  
***抜粋***
```
###③コントローラー
ストロングパラメーターでaddressを指定します。

```performances_controller.erb
before_action :set_performance, only: [:表示させるview]

def create
   @performance = Performance.new(performance_params)
   if @performance.valid?
     @performance.save
     redirect_to "/users/#{current_user.id}"
   else
     render :new
   end
end

def 表示させるview
    @performance = Performance.new(performance_params)
end

private

def set_performance
   @performance = Performance.find(params[:id])
end

def performance_params
 params.require(:performance).permit(:address).merge(user_id: current_user.id)
end
```
###④ビュー
CSSは別記してます。
zoomControl: false,
mapTypeControl: false,
fullscreenControl: false,
treetViewControl: false,
は拡大縮小ボタンなどを消す地図表示のオプションです。

```
<div id='map'>
<script>
let map
function initMap(){
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: <%= @performance.latitude %>, lng: <%= @performance.longitude %>},
    zoom: 15,
       zoomControl: false,
       mapTypeControl: false,
       fullscreenControl: false,
       streetViewControl: false,
  });

  marker = new google.maps.Marker({
    position: {lat: <%= @performance.latitude %>, lng: <%= @performance.longitude %>},
    map: map
  });
   geocoder = new google.maps.Geocoder()
}
</script>
  <script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_API'] %>&callback=initMap" async defer></script>
</div>
```
<b>※key=<%= ENV['GOOGLE_MAP_API'] %>の表記は充分気をつけてください!ここで＝の位置が違うだけで全てうまくいきません・・・</b>

###⑤モデル
これでgeocordが緯度経度を算出してカラムに保存してくれます

```performance.rb
geocoded_by :address
after_validation :geocode, if: :address_changed?
```
<b>※if: :address_changed?がないと作用しないことがあるので気をつけてください！私はこれを書かないとダメでした</b>

###⑥Geocording APIを使用するための記述
```
% rails generate geocoder:config
```
```/config/initializes/geocoder.rb

Geocoder.configure(
  # Geocoding options
  # timeout: 5,                 # geocoding service timeout (secs)
  lookup: :google,         # name of geocoding service (symbol)
  # ip_lookup: :ipinfo_io,      # name of IP address geocoding service (symbol)
  # language: :en,              # ISO-639 language code
  use_https: true,           # use HTTPS for lookup requests? (if supported)
  # http_proxy: nil,            # HTTP proxy server (user:pass@host:port)
  # https_proxy: nil,           # HTTPS proxy server (user:pass@host:port)
  api_key: 'YOUR_API_KEY',               # API key for geocoding service
  # cache: nil,                 # cache object (must respond to #[], #[]=, and #del)
  # cache_prefix: 'geocoder:',  # prefix (string) to use for all cache keys

  # Exceptions that should not be rescued by default
  # (if you want to implement custom error handling);
  # supports SocketError and Timeout::Error
  # always_raise: [],

  # Calculation options
  units: :km # :km for kilometers or :mi for miles
  # distances: :linear          # :spherical or :linear
)

```
#うまくいかない時の確認事項
・環境変数の設定
・viewの記述
・モデルのメソッド
・geocorder.rb

```
%rails c
[1] pry(main)> Geocoder.coordinates("〒150-0043 東京都渋谷区道玄坂２丁目１")
=> [35.6591376, 139.7007901]
```
で中身を変えながら出力されるか試してみる
・Google Map javascriptと、Geocoding APIのAPIkeyを一緒にしている場合、APIをもうひとつ作成し、別々にしてみる。
・本番環境での環境変数設定

```
[ec2-user@〜〜〜〜〜〜〜]$ sudo vim /etc/environment
```
変数設定後exit→再起動

```
[ec2-user@〜〜〜〜〜〜〜]$ env | grep YOUR_API_KEY
```
で確認
・EC2サーバーから再起動してみる（私はこれで最終的に本番環境で確認が取れました）