実務未経験者です。
ポートフォリオに組み込んだGoogleMapsAPI関連について、作っておきながら面談で全く説明できなかったので、
頭を整理するために流れをまとめたものを書いてみます。
アプリ: ラーメン屋の写真や情報を友達と共有できるSNS
Ruby: 2.6.5
Rails: 5.2.0
前提: GoogleCloudPlatformでAPIキーを取得すること
投稿内容から緯度経度情報を保存
postモデルでbefore_save時 (投稿保存する時)にgeocodeメソッドを呼ぶ。
geocodeメソッドでは、バリデーションの後にGeocoding APIを使って
店名と最寄駅情報から緯度経度を取得、緯度経度カラムに保存させている。
shop_nameカラム: 店名情報
nearestカラム: 最寄駅情報 (とてもわかりにくい)
latitudeカラム: 緯度情報
longitudeカラム: 経度情報
class Post < ApplicationRecord
~
~
before_save :geocode
~
~
private
def geocode
uri = URI.escape(
"https://maps.googleapis.com/maps/api/geocode/json?address="
+ self.shop_name
+ " "
+ self.nearest
+ "&key=" + Rails.application.credentials.GCP[:API_KEY] # APIキーを入れてください
)
res = HTTP.get(uri).to_s
response = JSON.parse(res)
if response["status"] == "OK"
self.latitude = response["results"][0]["geometry"]["location"]["lat"]
self.longitude = response["results"][0]["geometry"]["location"]["lng"]
else
self.latitude = 1
self.longitude = 1
end
end
end
geocordingAPIを使って緯度経度情報を取得するには、下記のURIを用います。
https://maps.googleapis.com/maps/api/geocode/json?address=緯度経度情報を調べたい住所など&key=APIキー
投稿詳細画面
・
・
<div class="post_map">
<div id="map"></div> <!-- cssでwidth, heightを指定しないと地図が表示されません -->
</div>
・
・
<script>
var latLng;
var marker;
var infoWindow;
function initMap() {
latLng = {lat: <%= @post.latitude %>, lng: <%= @post.longitude %>};
map = new google.maps.Map(document.getElementById('map'), {
center: latLng,
zoom: 15,
mapTypeControl: false,
streetViewControl: false
});
marker = new google.maps.Marker({
position: latLng,
map: map
});
infoWindow = new google.maps.InfoWindow({
content: "<a href='http://www.google.com/search?q=<%= @post.shop_name %> <%= @post.nearest %>' target='_blank' style='color: #00f;'><%= @post.shop_name %> を検索</a><br><br><a href='http://www.google.com/search?q=<%= @post.shop_name %> ラーメン&tbm=isch' target='_blank'>画像検索 by google</a>"
});
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
}
initMap();
</script>
<!DOCTYPE html>
<html>
<head>
<title>・・・・・・</title>
<!-- APIキーを読み込んでいます -->
<script src="https://maps.googleapis.com/maps/api/js?key=<%= Rails.application.credentials.GCP[:API_KEY] %>&callback=initMap" defer></script>
・
・
・
</head>
<body>
・
・
<%= yield %>
・
</body>
</html>
地図から投稿を検索できるようにする
form_with と radio_button で、どのユーザーの投稿を地図に表示させるか選択する
↓
mapsコントローラのmapアクションで、投稿内容を含む変数@postsを定義
(投稿内容は.to_jsonでjson形式に変換、respond_to doで返す)
↓
アクション名と同じmap.js.erbがRailsによって自動的に開かれ、@postsを受け取り、
地図とマーカー (投稿内容)をセット
<%= form_with url: map_request_path, method: :get do |f| %>
<%= f.radio_button :posts, "all_user", checked: true %>全てのユーザーの投稿
<%= f.radio_button :posts, "following", disabled: current_user.nil? %>自分とフォロー中のユーザーの投稿
<%= f.radio_button :posts, "current_user", disabled: current_user.nil? %>自分の投稿
<%= f.submit '投稿されたお店を表示', class: "btn btn-primary" %>
<button type="button" class="btn btn-success current_position" onclick="getLocation()">
地図を現在地周辺に切り替える
</button>
<% end %>
<div id="map_index"></div> <!-- cssでwidth, heightを指定しないと表示されません -->
<script>
var map
function initMap(){
map = new google.maps.Map(document.getElementById('map_index'), {
center: {lat: 37.67229496806523, lng: 137.88838989062504}, // 地図の中心を指定
zoom: 6, // 地図のズームを指定
mapTypeControl: false,
streetViewControl: false
});
}
function getLocation(){ // 現在地周辺に地図を移動させる
navigator.geolocation.getCurrentPosition(
function(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var latlng = new google.maps.LatLng(latitude, longitude);
map.setCenter(latlng);
map.setZoom(12);
}
);
}
initMap();
</script>
Rails.application.routes.draw do
~
~
resources :maps, only: [:index]
get '/map_request', to: 'maps#map', as: 'map_request'
end
class MapsController < ApplicationController
def index
end
def map
if params[:posts] == "all_user"
@posts = Post.all.to_json.html_safe
elsif params[:posts] == "current_user"
@posts = current_user.posts.to_json.html_safe
elsif params[:posts] == "following"
@posts = current_user.feed.to_json.html_safe
end
respond_to do |format|
format.js { @posts }
end
end
end
var posts = <%= @posts %>;
var marker = [];
var infoWindow = [];
function initMap(){
for (let i = 0; i < posts.length; i++) {
marker[i] = new google.maps.Marker({
position: {lat: parseFloat(posts[i].latitude), lng: parseFloat(posts[i].longitude)},
map: map,
animation: google.maps.Animation.DROP
});
infoWindow[i] = new google.maps.InfoWindow({
content: posts[i].shop_name + "<br>" + "<a href='/posts/" + posts[i].id + "' target='_blank' style='color: #00f;'>このお店に関する投稿を表示</a>"
});
markerEvent(i);
}
};
initMap();
function markerEvent(i) {
marker[i].addListener('click', function() { // マーカーをクリックしたとき
infoWindow[i].open(map, marker[i]); // 吹き出しの表示
});
}