31
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

大学生限定クリエイティブコミュニティGeekSalonAdvent Calendar 2021

Day 9

Google Mapを利用する 【Rails6】【Geocoder】【heroku】

Last updated at Posted at 2021-02-07

はじめに

この記事では, RailsアプリでGoogle Mapを利用する方法を書き記しています.

特徴は以下です.

  1. Google MapのAPIを利用します
  2. APIキーは公開防止のため, .envファイルで管理します.
  3. Mapの緯度経度情報をデータベースに登録することで, 場所の投稿サイトを作ることができます.
  4. 投稿された内容はMap上にピンを立てるようにします.
  5. 場所を投稿すると, 自動で緯度経度を取得し, データベースに登録するようにします.
  6. ピンの情報ウィンドウをクリックすると投稿の詳細ページへ飛びます

うまく動作しないときは, ディベロッパーツールのコンソールにエラー文が出力されるため参考にしましょう.

image.png

もくじ

  1. Google Map APIを利用可能にする
  2. MVCを用意する & その他設定
  3. herokuにAPIを登録する

1. Google Map APIを利用可能にする

Google MapはもちろんGoogleが発表しているサービスです. このようなサービスはAPIと呼ばれる仕組みを通して他と連携して利用することができるようになります. 具体的には, APIキーを登録します. 以下のページにて作業します.

Google Cloud Platform

※前提としてgoogleアカウントが必要です. また, 形式上Googleアカウントにクレジットカードを登録している必要があります.

プロジェクトの作成

以下の手順に従ってプロジェクトを作成します.

image.png

image.png

image.png

image.png

image.png

image.png

APIキーの作成

以下の手順に従ってAPIキーを作成します.

image.png

image.png

image.png

image.png

image.png

image.png

作成されたAPIキーは後で利用するのでどこかにメモしておきましょう!

請求先アカウント設定

Google Map APIを利用するには, 形式上請求先アカウントを設定する必要があります. 請求情報を紐づけるだけで, 無課金設定のまま利用できます.

image.png

「お支払い」から請求先アカウントを作成します. このとき, Googleアカウントにクレジットカードを登録している必要があります.
画面の指示に従って登録しましょう.

2. MVCを用意する & その他設定

上記でGoogle Map APIを利用するための準備が整いました. 今度は, 自分のRailsアプリの設定をしていきます.

この記事では, 一例として以下のようにmapsテーブルを作成します.
また, indexページにて, 場所の表示と場所の投稿を両方できるようにします.

maps テーブル

address latitude longitude
東京駅 35.6812 139.7671
... ... ...

mapsテーブル

以下のコマンドにより, address(住所), latitude(緯度), longitude(経度)を保存できるmapsテーブルを作成します.

$ rails g model Map address:string latitude:float longitude:float
$ rails db:migrate

mapsコントローラー

mapsコントローラー作成コマンド

$ rails g controller maps

コントローラーの記述は以下のようにします.

app/controllers/maps_controller.rb
class MapsController < ApplicationController
    def index
        @maps = Map.all
        @map = Map.new
    end

    def create
        map = Map.new(map_params)
        if map.save
            redirect_to :action => "index"
        else
            redirect_to :action => "index"
        end
    end

    def destroy
        map = Map.find(params[:id])
        map.destroy
        redirect_to action: :index
    end

    private
    def map_params
    params.require(:map).permit(:address, :latitude, :longitude)
    end
end

ルーティング

routes.rbにresources :mapsの一行を追加します.

congif/routes.rb
resources :maps 

viewファイル

app/views/maps/index.html.erb を作成し, テンプレートとして以下を記述します.

index.html.erb
<h2>Google map</h2>

<input id="address" type="textbox" value="">
<input type="button" value="地図を検索" onclick="codeAddress()">
<div id="display">緯度経度が表示されるよ!</div>

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

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

<script>
    let map

    const display = document.getElementById('display')

    // mapの表示関数 
    function initMap() {
        geocoder = new google.maps.Geocoder()

        // mapの初期位置, 縮尺を定義
        map = new google.maps.Map(document.getElementById('map'), {
            center: {
                lat: 35.6458437,
                lng: 139.7046171
            },
            zoom: 12,
        });

        // mapsテーブルにあるそれぞれのレコードをmap上に表示 
        <% @maps.each do |m| %>
            (function(){
            var contentString = "住所:<%= m.address %>"; 

            // マーカーを立てる
            var marker = new google.maps.Marker({
                position:{lat: <%= m.latitude %>, lng: <%= m.longitude %>},
                map: map,
                title: contentString
            });

            // 情報ウィンドウ(吹き出し)の定義
            // 投稿の詳細ページへのリンクも
            var infowindow = new google.maps.InfoWindow({
            position: {lat: <%= m.latitude %>, lng: <%= m.longitude %>},
            content: "<a href='<%= map_url(m.id) %>' target='_blank'><%= m.address %></a>"
            });

            // クリックしたときに情報ウィンドウを表示
            marker.addListener('click', function() {
            infowindow.open(map, marker);
            });

            })();
        <% end %>
    }

    let geocoder

    // 地図検索関数
    function codeAddress() {
        let inputAddress = document.getElementById('address').value;

        geocoder.geocode({
            'address': inputAddress
        }, function (results, status) {
            if (status == 'OK') {
                map.setCenter(results[0].geometry.location);
                var marker = new google.maps.Marker({
                    map: map,
                    position: results[0].geometry.location
                });

            display.textContent = "検索結果:" + results[ 0 ].geometry.location
            } else {
                alert('該当する結果がありませんでした:' + status);
            }
        });
    }
</script>

<script
    src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_API_KEY'] %>&callback=initMap"  
    async defer>
</script>

<h3>場所投稿フォーム</h3>
<%= form_for(@map, :url => { controller:'maps', action:'create'})do |f| %>
    
    <p>
    <%= f.label :address %>
    <%= f.text_field :address, size: "50x1" %>
    </p>

    <%= f.submit "送信"%>
<% end %>

<h3>場所一覧</h3>
<% @maps.each do |t| %>
    <p>住所 : <%= t.address %></p>
    <p>緯度 : <%= t.latitude %></p>
    <p>経度 : <%= t.longitude %></p>
    <p><%= link_to "削除する", map_path(t.id), method: :delete %></p>
    <hr>
<% end %>

投稿詳細(show)ページでmapを表示する場合は, 上記を参考に自分で作ってみてください!!

その他設定

Gemファイル & 環境変数の設定

Gemfileに以下二つのgemを追記します

gem 'geocoder'
gem 'dotenv-rails'

その後, bundle installします

$ bundle install

geocoderは住所(場所)から緯度経度を取得するGemです.
dotenv-railsは.envファイル(後述)を利用するためのGemです.

Map.rb(モデルファイル)

map.rbファイルは以下のように記述します.

app/models/map.rb
class Map < ApplicationRecord
    geocoded_by :address
    after_validation :geocode
end

addressが投稿されたら, 自動で緯度経度もデータベースに登録してくれます.

.envファイル

ルートディレクトリーに.envファイルを作成します.

image.png

これは, リリースするときに一般に公開したくない類のもの(APIキー)等を管理する用途で用います.

.envファイルにGOOGLE_MAP_API_KEY=xxxの一行を追記します.

このGOOGLE_MAP_API_KEY=xxx
右辺は先ほどメモしておいたGoogleのAPIキーを記述します.

.env
GOOGLE_MAP_API_KEY=ここに自分のAPIキーを書く

これは, maps/index.html.erbの

maps/index.html.erb
<script
    src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_API_KEY'] %>&callback=initMap"  
    async defer>
</script>

で用いられます.

公開しないように .gitignoreファイルに以下一行を記述します.

.gitignore
/.env

3. herokuにAPIを登録する

herokuにリリースするとき, GoogleのAPIキーをherokuにも登録する必要があります. 以下のxxxを自分のAPIキーに変えて, 実行することを覚えておいてください!

$ heroku config:set GOOGLE_MAP_API_KEY=xxxxxxxxxx
31
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?