【Ruby】RailsでGoogle Maps API(Geocording)を導入しよう
はじめに
使い勝手のよいwebアプリケーションを作成する上では、APIを理解しなければならない。今回は、APIやその他関連知識をまとめ、応用編として「Google maps API」を用いてアプリケーション作成できるようまとめている。
APIとは
[1]
APIの種類名称 | 提供者 | 具体例 |
---|---|---|
WebAPI | webサービスベンダー | GoogleAPIなど |
ネイティブAPI | オペレーティングシステム(OS) | WindowsAPIなど |
ライブラリAPI | フレームワーク | 〇〇Frameworkなど |
ランタイムAPI | ランタイム環境 | Ruby on RailsAPIなど |
データベースAPI | データベースサービスベンダー | OCLAPIなど |
APIの提供方式
名称 | 利用者 |
---|---|
パブリックAPI | 登録すれば誰でも利用できる |
ビジネスAPI | 課金契約で利用 |
メンバーAPI | コミュニティメンバーで利用 |
パートナーAPI | パートナー企業内で利用 |
クローズドAPI | 社内・組織の内部で利用 |
プライベートAPI | 特定のユーザーのみで利用 |
APIの仕組み
APIはユーザーが必要とするたびに利用(リクエスト)され、その応答(レスポンス)を得ることで利用される。
例)
ECサイトでユーザーがクレジットカードを用いて決済する機能でAPIを用いた場合、ECサイト側でクレジットカードの決済機能を開発する必要はなく、クレジットカード運営会社が用意しているAPIを通じてカード番号や氏名などの情報を含めリクエストすると、決済の可否を表すレスポンスが返ってくるようになっている。
SDKとは
Google Maps APIの全体を把握しよう
Goolge Maps APIの種類
API名 | 内容 |
---|---|
JavaScript API | Google Maps をウェブサイトに表示 |
Static Maps API | 地図画像を高解像度で表示 |
Street View Image API | ストリートビュー画像を高解像度で表示 |
Directions API | 最適化された経路検索を自動で行うことが可能 |
Distance Matrix API | 社内・複数の始点・終点の組み合わせルートの「距離」「時間」を求められる |
Roads API | 道路に沿ったスムーズなパスを取得します、また制限速度情報を返す |
Geolocation API | GPS 機能が無い環境でユーザーの位置情報を特定可能 |
Places API | 施設検索の API、一億件以上の詳細情報を検索・表示可能 |
Geocording API | 住所を緯度・経度(または緯度経度を住所)に変換可能 |
Elevation API | ある地点の標高(高さ)を取得可能 |
Time Zone API | ある地点のタイムゾーン(時間帯)を取得可能 |
今回は「java script API」と「Geocording API」と「Places API」を実装していく。
JavaScript APIとGeocording APIとPlaces APIを活用してみよう。
1.Google Cloud Platformの登録する。
GCP登録画面
2.メニューバーからAPIとサービスを選択する。
3.ダッシュボードからプロジェクトを作成する。
4.認証情報から「認証情報を作成」を押し「APIキー」を選択する。
5.APIキーが作成されたことを確認する。
6.可能であれば作成されたAPIキーに制限をかける。
- ウェブサイトの場合はウェブサイトを選択し、ADDからURLを追加する。
- IPアドレスの場合はターミナルからipconfigコマンドを実行し、IPアドレスを確認する。
7.検索フォームに「Maps Javascript API」と入力し、そのAPIを有効にする。同様のやり方で「geocoding API」「places API」を有効にする。
------------- ここからは、VScode(エディタ)の方 -----------
8.環境変数を管理するために[dotenv]をインストールする。
gem 'dotenv-rails'
bundle install
yarn add dotenv
出力結果
$ yarn add dotenv
yarn add v1.22.22
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning " > @babel/plugin-proposal-private-methods@7.18.6" has unmet peer dependency "@babel/core@^7.0.0-0".
warning "@babel/plugin-proposal-private-methods > @babel/helper-create-class-features-plugin@7.24.1" has unmet peer dependency "@babel/core@^7.0.0".
warning "@babel/plugin-proposal-private-methods > @babel/helper-create-class-features-plugin > @babel/helper-replace-supers@7.24.1" has unmet peer dependency "@babel/core@^7.0.0".
warning " > @babel/plugin-proposal-private-property-in-object@7.21.11" has unmet peer dependency "@babel/core@^7.0.0-0".
warning "@babel/plugin-proposal-private-property-in-object > @babel/helper-create-class-features-plugin@7.24.4" has unmet peer dependency "@babel/core@^7.0.0".
warning "@babel/plugin-proposal-private-property-in-object > @babel/plugin-syntax-private-property-in-object@7.14.5" has unmet peer dependency "@babel/core@^7.0.0-0".
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ dotenv@16.4.5
info All dependencies
└─ dotenv@16.4.5
Done in 15.02s.
9.[.env]ファイルを作成する。
touch .env
10.[.gitignore]ファイルに[.env]を追加する。
/.env
11.[.env]ファイル内に作成したAPIキー(Maps Javascript API/geocoding API)を記載し、読み込めるようにする。
GOOGLE_MAPS_API_KEY="AAAAAABBBBBBCCCCCDDDDD"
GEOCODING_API_KEY="AAAAAABBBBBBCCCCCDDDDD"
PLACES_API_KEY="AAAAAABBBBBBCCCCCDDDDD"
この記載を行うことでRails(index.html.erb)ファイル内で、ENV["GOOGLE_MAPS_API_KEY"]
やENV["GEOCODING_API_KEY"]
やENV["PLACES_API_KEY"]
と記載することで、環境変数を表現することができるようになる。
12.javascriptでAPIキーを読み込めるようにする。
require("dotenv").config(); // 追加
const { environment } = require('@rails/webpacker')
module.exports = environment
Google Maps APIは基本的にjava scriptで動作する。そのため、APIキーはjava scriptのコード内で必要となってくるため記載する必要がある。上記ファイル内に記載を追加することで、Railsとjava scriptの両方で環境変数を読み込むことができるようになる。
13.「geocoder Gem」と「google_places Gem」のインストールする。
gem 'geocoder'
gem 'google_places'
bundle install
14.geocoderの設定ファイルを作成し、Geocoding APIを連携させる。
rails g geocoder:config
実際の画面
lookup:
,user_https
,api_key
,units
の項目を変更する。
Geocoder.configure(
# Geocoding options
# timeout: 3, # 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: ENV["Geocoding_API_Key"],# API key for geocoding service
# cache: nil, # cache object (must respond to #[], #[]=, and #del)
# 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
# Cache configuration
# cache_options: {
# expiration: 2.days,
# prefix: 'geocoder:'
# }
)
15.Geocodingの機能を使用するためにマイグレーションファイルを作成する。
rails g migration AddGeocodingColumnToPosts address:string latitude:float longitude:float
作成されたマイグレーションファイルを編集する。
class AddGeocodingColumnToPosts < ActiveRecord::Migration[6.1]
def change
add_column :posts, :address, :string, null: false, default: ""
add_column :posts, :latitude, :float, null: false, default: 0
add_column :posts, :longitude, :float, null: false, default: 0
end
end
rails db:migrate
16.Postモデルでgeocodingを使えるようにする。
class Post < ApplicationRecord
:
:
validates :address, presence: true
geocoded_by :address
after_validation :geocode
:
:
end
コードの意味
geocoded_by :address
で、addressカラムの内容を緯度・経度に変換する
after_validation :geocode
で、バリデーションの実行後に変換処理を実行して、latitudeカラム・longitudeカラムに緯度・経度の値が入力される。
17.places apiの設定ファイルを作成し、下記コードをファイル内に追加し、places APIを連携させる。
config/initializers/google_places.rb
GooglePlaces.configuration do |config|
config.api_key = ENV['PLACES_API_KEY']
end
18.フォームから住所を入力できるようにする。(places APIによりフォームの補完が効く)
<h1>Hello</h1>
<%= form_with model: @post, url: posts_path, method: :post, id: 'post-form' do |f| %>
<div>
<%= f.label :title, "タイトル" %><br>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :body, "本文" %><br>
<%= f.text_area :body %>
</div>
<div>
<%= f.label :images, "画像" %><br>
<%= f.file_field :image, accept: "image/*" %>
</div>
<!-- 補完機能の付いた住所フォームが作成できる -->
<div>
<%= f.label :address, "住所" %><br>
<%= f.text_field :address, id: 'address-input' %>
</div>
<div>
<%= f.submit "投稿" %>
</div>
<% end %>
<!-- places APIを読み込む -->
<script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['PLACES_API_KEY'] %>&libraries=places"></script>
<!-- 上にある住所のフォーム内にテキストが入力された際の動的な処理 -->
<script>
document.addEventListener('DOMContentLoaded', function() {
var addressInput = document.getElementById('address-input');
var autocomplete = new google.maps.places.Autocomplete(addressInput);
// 選択された住所をフォームの住所フィールドにセット
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
addressInput.value = place.formatted_address;
});
});
</script>
posts_controller.rb
)の記述をする。
19.コントローラ(class PostsController < ApplicationController
def index
@posts = Post.all
end
def create
@post = current_user.posts.build(post_params)
result = Geocoder.search(@post.address).first
if result
@post.latitude = result.latitude
@post.longitude = result.longitude
end
if @post.save
redirect_to posts_path
else
render :new
end
end
private
def post_params
params.require(:post).permit(:title, :body, :image, :address,)
end
end
コードの解説
result = Geocoder.search(@post.address).first
①Geocoder.seach
メソッドを用いて、ストロングパラメータの中にあるaddress
の中身の緯度と経度を探す。
if result
@post.latitude = result.latitude
@post.longitude = result.longitude
end
②その投稿(post
)のlatitude
=緯度とlongitude
=経度をそれぞれ代入し、表示に用いる。
20.地図を表示するためにビューファイルにjava scriptのコードを記述する。
<div id="map" style="height: 600px;"></div>
<script>
function initMap() {
// 地図要素を取得する(マーカーを表示させるために必要)
const mapElement = document.getElementById('map');
const mapOptions = {
center: {lat: <%= @post.latitude %>, lng: <%= @post.longitude %>},
zoom: 15
};
const map = new google.maps.Map(mapElement, mapOptions);
// マーカーを追加(Postの情報からマーカーを追加する)
const maker = new google.maps.Marker({
position: {lat: <%= @post.latitude %>, lng: <%= @post.longitude %>},
map: map,
title: '<%= j @post.title %>'
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV["GOOGLE_MAPS_API_KEY"] %>&callback=initMap"></script>
http://localhost:3000/posts/new
にアクセスし、投稿を行う。
21.
http://localhost:3000/posts/4
投稿した内容を確認する。(post/の後は投稿のid)
22.お疲れ様でした。
終わりに
APIを用いるにはAPIキーが必要であり、それは機密情報として扱われるため、アプリケーション内の.env
ファイル内に保管され、web上にアップされないようgitignore
ファイルに記載する必要があることがわかった。Google maps APIを用いたが、世の中には数えきれないほど便利なAPIが多く存在する。これを機に様々なAPIを用いてwebアプリケーション開発にチャレンジしていきたい。
参考
Discussion