2
11

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.

【ポートフォリオ】マップピンをクリックしてpost情報を取り出す【GoogleMap API】

Last updated at Posted at 2020-12-12

今回ポートフォリオでGoogleMap APIを使ったアプリケーションを開発したので
その方法の一部をお伝えしたいと思います。

この記事通り記述すれば、マーカークリックと同時に投稿を表示したり、特定の画面を表示させたりと色々なことができるようになります。
ポートフォリオでGoogleMap APIを取り入れようと考えている方は是非参考にしてみてください。

又、これからポートフォリオに取り組む方も、WebAPIを使っていると加点要素にはなると思うので
これを機に検討してみてはいかがでしょう。

それでは行きましょう!

目次

1.こういうことができる
2.前提
3.手順
3-1.javascriptでマップの緯度経度情報をwebサーバーに送る。
3-2.Railsのコントローラーで緯度経度が合致する投稿をDBから見つけてくる。
3-3.投稿データを配列に入れる。
3-4.javascriptで配列から値を取り出す。

こういうことができる↓

ezgif.com-gif-maker (3).gif

前提

■ 投稿テーブル(posts)と地図テーブル(maps)が作成されている、
投稿時に緯度経度情報も同時に登録できるようになっていること。
そもそも投稿と同時に緯度経度の登録ってどうやるんだよという人の為に、きっと今度記事を書きます。。

又、地図テーブルには緯度カラム(latitude)、経度カラム(longitude)がある状態とします。
なければあとから追加してください。

テーブルのカラムはこんなイメージ

posts maps
body latitude
hoge longitude
piyo post_id

また緯度・経度カラムのデータ型はdecimal型かfloat型を指定する必要があります。
緯度経度は座標なので、小数点以下5~6位くらいまであれば良さそうですので、浮動小数を含むデータ型(=decimalかfloat)にしましょうというお話しです。
浮動小数のことを考えないと、地図上で近い位置をクリックした際に近接する別の緯度経度を拾ってしまう可能性があるからです。

ということで今回はfloat型で進めます。
decimalでやる場合はこちらを参照すると良いと思います。
(厳密にはfloat型を扱う…というよりdouble型というデータ型を用いるのですが、Rails上ではdoubleを扱えないのでfloat型に桁数指定をする形で進めます。)

■ GoogleMap javascript APIは導入済みというところからスタートします。
まだの方はこちらを参考にしてください。すぐ終わります。

手順

1.javascriptでマップの緯度経度情報をwebサーバーに送る。
2.レスポンスを受け取り、Railsのコントローラーで緯度経度が合致する投稿をDBから見つけてくる。
3.投稿データを配列に入れる。
4.javascriptで配列から値を取り出す。

ナンノコッチャわからないと思いますが、この流れで行きますので
もし今何をしているのかわからなくなったらここへ立ち返りましょうー。

1.javascriptでマップの緯度経度情報をwebサーバーに送る

javascriptで以下の記述をします。

古の技術XHRを使っていますが、そこは言い合いっ子なしでお願いします。。だって参考書にそう書けってかいてあったんだもん!←情弱
余裕がある方はfetchとか使うとナウいらしいです。

XHRとはなんぞやという人はこちらを見てください。
ざっくり説明するとAjaxでサーバーにリクエストを送り、レスポンスをもらう方法です。

application.js
//マーカークリック時の関数
function dispInfo(marker,name) {
  google.maps.event.addListener(marker, 'click',
    function(event) {
		
			//HTML上の 'id = search_mark' の直下に投稿内容を生成していきます。
	    var search_mark = document.getElementById('search_mark')
			//XHRを行う宣言
      var xhr = new XMLHttpRequest();
			//xhrでリクエストするURIをここで書く。latlngsearchはここで定めた任意の値です。後で説明します。
			//marker.position.lat()はGoogleMap側のライブラリで定義されているオブジェクトとメソッド。マーカー位置の緯度が取れる。lng()は経度。
			//JSON形式にしているのはJSONにしとくと何かと取り回しがきくので。
      xhr.open('GET', "/latlngsearch/" + marker.position.lat() + "/" + marker.position.lng() + ".json", true)
      xhr.send(null);
			//通信に成功したとき初めて次のステップに行くようにする。
      xhr.onreadystatechange = function() {
        if(xhr.readyState === 4 && xhr.status === 200) {
          var post_datas = JSON.parse(xhr.responseText)
          if (post_datas === null){
            search_mark.textContent = '投稿データがないよ'
          }else{
						//JSONの0項=投稿情報をpost_dataとする。この後で詳しく書く。
						var post_data = post_datas[0];
						
						//クリックしたマーカー(投稿)のbodyを生成
            var div_tag_body = document.createElement('div');
            var a_tag_body = document.createElement('a');
            var text_body = document.createTextNode(post_data.body);
            a_tag_body.appendChild(text_body);
            div_tag_body.appendChild(a_tag_body);
            search_mark.appendChild(div_tag_body);	
					}
        }
      }
    }
  )
}

これで、マーカーをクリックした時にXHRが送られるようになりました。
つまりwebサーバーに緯度経度の情報を送ることができたわけです。

そしてwebサーバーにリクエストを送ったら、そのリクエストをRailsがどうルーティングするか書いておきましょう。

routes.rb
  get 'latlngsearch/:lat/:lng' => 'posts#search', constraints: { lat: /\d+\.\d+/, lng: /\d+\.\d+/ }

これだけどこでもいいので追記してください。
先程javascriptで記述した
xhr.open('GET', "/latlngsearch/" + marker.position.lat() + "/" + marker.position.lng() + ".json", true)
が効いてきます。

このリクエストの意味は
httpメソッドは'GET'で、指定したURIのアクションを開く
という意味なので、それに従いRailsは「GETメソッドを持ち、/latlngsearch/からはじまるURIのルーティング」を選択します。

:lat:lngに入る値はjavascriptで記述した通り、マーカーの緯度と経度になります。
又、constraintsに続く一文は正規表現で『(数字が何文字か).(数字が何文字か)』を表しています。つまり座標っぽいモノ以外は入れないよという意味です。

余談になりますが、正規表現がわからないと呪文に見る記号群も一度知ればなんてことはないので、気になる方は[こちら伊藤潤一さんの記事を見てみると勉強になりますよ。][5]
[5]:(https://qiita.com/jnchito/items/893c887fbf19e17d3ff9)

これで緯度・経度をRubyで受け取れました。
あとは緯度・経度から投稿を引っ張り出して、又JSに渡せばほぼ完成です!

続いてはpostsコントローラーのsearchアクションを実行しますので、次でそれを書いていきましょう。

2コントローラーで緯度経度が合致する投稿をDBから見つけてくる

3.投稿データを配列に入れる。

ここでは一気に2つ進みます。

routes.rbでsearchアクションを実行するよう記述したので、記述した以上はsearchアクションを書いてあげないとroutes.rbに恨まれてしまいます。書きます。

で何を書くかというと

1.mapsテーブルから緯度経度が合致する投稿を見つける。
2.それを配列にいれる

post_controller.rb
  def search
    maps = Map.where(latitude: params[:lat]).where(longitude: params[:lng])
    @marker_arr =[]
    maps.each do |map|
			#pushメソッドは配列に値を入れるメソッド
      @marker_arr.push(map.post)
    end

ここでeach文を使っているのは仮に同じ座標に複数投稿があったときに、片方だけ代入されることを防ぐ為です。

又、投稿に紐づくuserのデータなどがほしければ @marker_arr.push(map.post.user) などを追記してあげれば、それも配列として使えます。

さあ、マーカーをクリックしてからその緯度・経度(map)が紐づく投稿(post)を作れました!
あとはこれをJSに渡せばゴールです!

4.javascriptで配列から値を取り出す。

今までXHRで送ったリクエストをwebサーバー上のRailsがゴニョゴニョしてきました。
あとはレスポンスとしてJSに返すだけんですが、返す時にJSONにして返したいので、jbuilderというgemを使います。

JSONに変換する

「ここに来て未知のもの触りたくねー」と思ったあなた!jbuilderはrails(4からデフォルトになっているそうです)に標準で入っているgemです。
ですのでbundle installする必要もありませんし、今後もよく使う(らしい)ので一度使っておいて損はないと思います。

このjbuilderはデータをJSONに変換してくれます。
[jbuilderについてはこちら][6]
[6]:(https://pikawaka.com/rails/jbuilder)

下記のようにjbuilder用のファイルを作成し記述します。

search.json.jbuilder
json.array! @marker_arr

これによって配列に格納されたJSONデータを生成します。
つまり投稿データをJSONにできました。

さあ、いい加減javascriptにレスポンスを返しましょう!ぴゅーん

受け取ったJSONをHTMLとして生成する

レスポンスをJSで受け取る記述は既に書きましたね。

var post_datas = JSON.parse(xhr.responseText)

JSON.parseでJSONとしてデータを受け取り、post_datasにデータを入れました!
あとは先程JSに書いた通りHTMLを生成して終了です。

おわりに

マーカーをクリックした際に色々なことができると書きましたが、ボリュームの都合上本記事では取り上げませんでした。
ただやることはJSのfunction(event) {の下にやりたいことを書くだけです。

しかし、実務未経験でポートフォリオを作っている段階だとjavascriptの書き方、チンプンカンプンですよね。
私は一冊本を買って、コピペ、ググりを繰り返し何となく読める書けるようになりました。

下記の『javascript本格入門』が評判も良く、わけも分からずとりあえず触った程度の人間にもちょうどよく感じました。
ただ出版は2016年なのでXHRのような多少古びた技術を取り上げていたりしましたが、そのへんはGoogle先生と肩を組んで行きましょう!

それでは!

2
11
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
2
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?