LoginSignup
5
4

More than 3 years have passed since last update.

投稿された住所をマップに反映させるRailsアプリを作る

Posted at

Railsで、ユーザが投稿した住所をマップ上に表示させるアプリを作りました。
ごくごく簡単なものになりますのでササッと。

アプリケーションの動き

  1. ユーザーがフォームから住所を投稿
  2. 住所を緯度経度に変換
  3. 変換した移動軽度から、画面上のマップにマーカーを反映させる。

な感じです。

準備

駆け足で書いていくため、最初の手順は省きます。
取り敢えず、
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 &copy; <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)カラムも更新してくれます。

完成

上記の手順でおそらく完成するはずです。
FireShot Capture 023 - MapTest - mrbicycle-map-test.herokuapp.com.png

寝る前にササッと書いているのでかなり駆け足でしたが、お読み頂きありがとうございました。

5
4
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
5
4