Railsで、ユーザが投稿した住所をマップ上に表示させるアプリを作りました。
ごくごく簡単なものになりますのでササッと。
アプリケーションの動き
- ユーザーがフォームから住所を投稿
- 住所を緯度経度に変換
- 変換した移動軽度から、画面上のマップにマーカーを反映させる。
な感じです。
準備
駆け足で書いていくため、最初の手順は省きます。
取り敢えず、
rails new
がされている状態から始めます。
Gemfileに追記
Gemfileに以下を加え、bundle installを実行します。
# map表示を簡易化する
gem 'leaflet-rails'
# map上のマーカー周りをゴニョゴニョする
gem 'leaflet-markercluster-rails'
# 住所を緯度経度に変換する
gem 'geocoder'
設定ファイルを追加
config/initializersに以下のファイルを追加
Leaflet.tile_layer = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
Leaflet.attribution = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>'
Leaflet.max_zoom = 18
特に難しい設定ではなくて、見てのとおりですね
tile_layerを書き換えれば、OpenStreetMapだけでなくgoogle mapやらも使うことが出来ます。
scaffoldでササッと投稿アプリを制作
Railsの魔法ことScaffoldで、簡単にユーザー投稿アプリを作ります。
rails g scaffold maps name address comment:text lonlat
それぞれ
- name:住所を投稿したユーザの名前(なくていい)
- address:投稿された住所
- comment:なにかしらのコメント
- lonlat:投稿された住所を(内部的に)緯度経度変換し保存する
です。
緯度経度(lonlat)はユーザーに入力させたくないので、_form.html.erbから該当箇所を削除しておきます。
最後にrails db:migrate
も実行。
leafletでマップを表示する
今回は『Open Street Map』を使用します。
leafletを使うための準備
まずleafletを使用するため、application.jsとapplication.cssに以下を追加します。
application.js
//= require leaflet
//= require leaflet.markercluster
application.css
*= require leaflet
*= require leaflet.markercluster
*= require leaflet.markercluster.default
*/
適当なマーカー用画像を用意
今回は、取り敢えず"marker.png"という画像を/Publicに追加したということで進めます。
leafletを使ってマップを表示
maps/indexに以下のコードを追記します。
(省略)
<div id="map" style="height: 500px; width: 500px;"></div>
<%=
map(:center => {
:latlng => [36, 140],
:zoom => 4,
})
%>
<script>
// rubyから渡された住所配列をjsの変数に格納
var maps = <%= @maps.to_json.html_safe %>;
for(var hash_count = 0; hash_count < maps.length; hash_count++){
// 緯度経度とコメントを取り出しマーカー化
L.marker(maps[hash_count].lonlat.split(','), {icon: L.icon({iconUrl: "/marker.png"})},)
.bindPopup(maps[hash_count].comment)
.addTo(map);
}
</script>
scriptタグの中はこちらの書き方の方がスマートでいいですね
<% @maps.each do |map| %>
L.marker("<%= map.lonlat %>".split(','), {icon: L.icon({iconUrl: "/cycle24.png"})},)
.bindPopup("<%= map.comment %>")
.addTo(map);
<% end %>
投稿された住所を緯度経度に変換する
ユーザーが住所を入力し保存(あるいは更新)する際に、住所を緯度経度に変換しlonlatカラムに保存するための仕組みを作ります。
class Map < ApplicationRecord
before_save :update_lonlat
def update_lonlat
lonlat = address_to_lonlat(read_attribute(:address))
write_attribute(:lonlat, lonlat)
end
# 住所を保存用経緯度に変換
def address_to_lonlat(address)
result = Geocoder.search(address)
lonlat = result.first.coordinates
return lonlat.join(',')
end
end
これだけで、住所(address)カラムを保存、更新した際に緯度経度(lonlat)カラムも更新してくれます。
完成
寝る前にササッと書いているのでかなり駆け足でしたが、お読み頂きありがとうございました。