##はじめに
・Maps JavaScript API
・Geocoding API
上記のAPIを使用して個人アプリの制作で地図を含んだ投稿をして、表示させる処理を実装しました。
いろいろな記事を参考にさせていただきでき結構ハマったのでまとめておきます。
※地図以外の投稿機能はできているものとしてまとめています
追記
【rails】GoogleMapsAPI 緯度、経度が保存できない時の記述
自分は緯度、軽度がうまく取得できていなかったので、同じような方がいましたらこちらの記事も参考にしてください。
#実装内容・イメージ写真
1.ユーザーに地名もしくは住所を入力してもらう
2.詳細ページにてgooglemapにマーカーを落として表示させる
###投稿時
※フロント部分はほぼデフォルトのままですご了承ください。
#Google API
googlemapを使用するときはAPIを取得しなければいけません。
下記リンクからAPIのKEYを取得してください。
Google Maps Platform
取得方法については今回は割愛します。
今回作成したアプリでは
・Maps JavaScript API
・Geocoding API
を使用しますので有効にしておいてください。
#データベース作成
まずデータベースを作成します。
既に作成済みの場合はカラムを追加してください。
##postテーブル
Column | Type | Options |
---|---|---|
title | string | null: false |
text | text | null: false |
###Association
has_one :spot
##spotテーブル
Column | Type | Options |
---|---|---|
address | string | null: false |
latitude | float | null: false |
longitude | float | null: false |
review_id | references | foreign_key: true, null: false |
###Association
belongs_to :post
#gemのインストール
gem "gmaps4rails"
gem "geocoder"
gem "gon"
gem "dotenv-rails"
Gemfileに記述できたらbundle installをしてください。
上から
・GoogleMapを簡単に作成できるgem "gmaps4rails"
・地名から緯度経度に変換できるgem "geocoder"
・JSでcontrollerの変数を使えるようにするgem "gon"
・GoogleMapAPIのkeyを隠すためのgem "dotenv-rails"
#JS導入
###application.html.hamlを編集
!!!
%html
%head
.
.
.
= include_gon
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
%body
= yield
%script{src: "https://maps.googleapis.com/maps/api/js?key=#{ENV["GOOGLE_MAP_KEY"]}&callback=initMap"}
%script{src: "//cdn.rawgit.com/mahnunchik/markerclustererplus/master/dist/markerclusterer.min.js"}
%script{src: "//cdn.rawgit.com/printercu/google-maps-utility-library-v3-read-only/master/infobox/src/infobox_packed.js", type:"text/javascript"}
%head内にはgem "gon"を使えるようにするための記述をします。
%body内にはJSを使うための記述をしています。%head内に記述する方法もあると思いますが今回は%body内に記述しました。
ENV["GOOGLE_MAP_KEY"]には.envファイルに隠したAPIKEYを入れています。
GOOGLE_MAP_KEY = "取得したAPIKEYを記述してください"
.envファイルを作成して上記を記述します。
###underscore.jsを作成
app/assets/javascripts下にunderscore.jsを作成して下記リンク先のコードをコピペして貼り付けます。
###application.jsを編集
application.jsを編集します。
//= require underscore
//= require gmaps/google
#modelの編集
次に各modelを以下のように編集します。
class Post < ApplicationRecord
has_one :spot, dependent: :destroy
accepts_nested_attributes_for :spot
end
class Spot < ApplicationRecord
belongs_to :post
geocoded_by :address
after_validation :geocode
end
#viewの編集
投稿ページを作成します。googlemapの投稿、表示のぶぶの記述しています。
住所や場所の名前を入力するフォームを作成します。
= form_with(model: @post, local: true, multipart: true) do |f|
.spot
= f.fields_for :spot do |s|
= s.label :address, "レビュー場所(Google Mapで検索)", class: 'spot__title'
= s.text_field :address, placeholder: "スポットを入力", id: "address", class: 'spot__text'
%input{onclick: "codeAddress()", type: "button", value: "検索する"}
.map{id: "map", style: "height: 320px; width: 640px;"}
次に投稿された詳細ページのgooglemapの部分を記述します。
.show
.show__address
= @post.spot.address
.show__maps{id: "show_map", style: "height: 320px; width: 400px;"}
#controllerの編集
controllerを編集します。
def new
@post = Review.new
@post.build_spot
end
def create
@review = Review.new(review_params)
if @post.save
redirect_to root_path
else
redirect_to new_review_path
end
end
def show
@post = Review.find(params[:id])
@lat = @review.spot.latitude
@lng = @review.spot.longitude
gon.lat = @lat
gon.lng = @lng
end
private
def review_params
params.require(:post).permit(:title, :text,spot_attributes: [:address])
end
newアクションの.buildメソッドではhas_oneの関係にあたるので
@post.build_spot
としています。
showアクションで記述している
@lat = @review.spot.latitude @lng = @review.spot.longitude gon.lat = @lat gon.lng = @lng
では、controllerで定義した@lat
と@lng
の変数をJavaScriptでも扱えるように、それぞれgon.lat
とgon.lng
に代入しています。
#JavaScriptの作成
次にJavaScriptファイルを作成していきます。
asset/javascripts/ 内に googlemap.js を作成します。
let map //変数の定義
let geocoder //変数の定義
function initMap(){ //コールバック関数
geocoder = new google.maps.Geocoder() //GoogleMapsAPIジオコーディングサービスにアクセス
if(document.getElementById('map')){ //'map'というidを取得できたら実行
map = new google.maps.Map(document.getElementById('map'), { //'map'というidを取得してマップを表示
center: {lat: 35.6594666, lng: 139.7005536}, //最初に表示する場所(今回は「渋谷スクランブル交差点」が初期値)
zoom: 15, //拡大率(1〜21まで設定可能)
});
}else{ //'map'というidが無かった場合
map = new google.maps.Map(document.getElementById('show_map'), { //'show_map'というidを取得してマップを表示
center: {lat: gon.lat, lng: gon.lng}, //controllerで定義した変数を緯度・経度の値とする(値はDBに入っている)
zoom: 15, //拡大率(1〜21まで設定可能)
});
marker = new google.maps.Marker({ //GoogleMapにマーカーを落とす
position: {lat: gon.lat, lng: gon.lng}, //マーカーを落とす位置を決める(値はDBに入っている)
map: map //マーカーを落とすマップを指定
});
}
}
function codeAddress(){ //コールバック関数
let inputAddress = document.getElementById('address').value; //'address'というidの値(value)を取得
geocoder.geocode( { 'address': inputAddress}, function(results, status) { //ジオコードしたい住所を引数として渡す
if (status == 'OK') {
let lat = results[0].geometry.location.lat(); //ジオコードした結果の緯度
let lng = results[0].geometry.location.lng(); //ジオコードした結果の経度
let mark = {
lat: lat, //緯度
lng: lng //経度
};
map.setCenter(results[0].geometry.location); //最も近い、判読可能な住所を取得したい場所の緯度・経度
let marker = new google.maps.Marker({
map: map, //マーカーを落とすマップを指定
position: results[0].geometry.location //マーカーを落とす位置を決める
});
} else {
alert('該当する結果がありませんでした');
}
});
}
上記の記述についてはhttps://qiita.com/kanato4/items/f2f3f7accd880224616a
を参考にさせていただきました。
#終わりに
以上なります!
初めてgoogleAPIを使用したアプリケーションの作成でこの部分だけでかなりの時間を使ってしまったので後学者のためにもし参考になれば幸いです。