Rails5でGeocorderとGeolocationを使って周辺の施設を検索する方法

Rails5でGeocorderとGeolocationを使って周辺の施設を検索する方法:

Railsでアプリケーションを作っている時に位置情報を使って周辺の施設(自分の場合は飲食店)を検索する機能を付けたいと思ったので今後、位置情報を使う時にメモの代わりになればいいかなと思ったので書きます。

最後の方で壊滅的な事に気づいたのでそれも書きますww

ではやっていきましょう!!


前提

Rails 5.0.0

Ruby 2.5.3

下記を含むモデルがある事

t.string "prefecture"   都道府県 
t.string "address_city"   区市 
t.string "address_street"   町 
t.string "address"   都道府県+区市 
ブラウザに位置情報を使用する事が許可されている事


手順

gem導入



住所をgeocording



緯度経度をそれぞれカラムへ保存



現在地情報をgeolocationを使って取得



検索


gemの導入

Gemfile
gem 'geocoder' 


住所をgeocording

モデルにfloat型でlatitudeとlongitudeを追加

モデル.rb
t.float "latitude" 
    t.float "longitude" 
ここで気づいたのですが実はgeocorderはスポットに強い代わりに住所に対して弱く

どういう事かというと「スカイツリー」で緯度経度を保存しようとすれば正確な緯度経度が出るのですが

「東京都墨田区押上1丁目1−2」で保存しようとすると緯度経度が出ず、「東京都墨田区」までしか出ませんwww

結論を述べるとgeocorderでは無く、googleのAPIを使用する方が正確な緯度経度を取得出来ます。

自分もそれに手を付け始めたので完成したらその記事はまた書きます!(今書けよ、、)


緯度経度をそれぞれカラムへ保存

自分の場合は住所をそれぞれ都道府県、市、区、町村、番地とそれぞれ別のカラムに保存したので都道府県、市、区までのカラムから緯度経度を出します。

なので、自分はgeocording用にaddressカラムを作ってその中に、都道府県、市、区の3つだけを入れました。

その前にgeocorderにどのカラムから緯度経度を出すか教えてあげましょう!

この2行をモデルに追加してあげます。

下の行はどのタイミングでgeocordingするかです。この書き方だと住所が編集された時となります。(これ以外知らない、、)

モデル.rb
geocoded_by :address 
    after_validation :geocode, if: :address_changed? 
これは自分の場合ですが一応書いときます。

コントローラ
def create 
        @shop = Shop.new(shop_params) 
        @shop.address = @shop.prefecture + @shop.address_city 
        @shop.address = @shop.address.gsub(/\d+/, "").gsub(/\-+/, "") 
        @shop.save 
    end 


現在地情報をgeolocationを使って取得

下はHTMLに組み込まれてるAPI(自信はない、、)を使用するスクリプトです。

これを書き込んだViewにはこんな感じのボタンを入れてください。

View
<button onclick="getPosition();">Find!!</button> 
適宜使いたいView
<script> 
 
    // 現在地取得処理 
    function getPosition() { 
      // 現在地を取得 
      navigator.geolocation.getCurrentPosition( 
        // 取得成功した場合 
        function(position) { 
            window.location.href = "/shops/search_location?latitude="+position.coords.latitude+"&longitude="+position.coords.longitude 
            // $.ajax({ 
            //   url: "/shops/search_location", 
            //   type: "GET", 
            //   dataType: 'html', 
            //   data: {latitude : position.coords.latitude, 
            //         longitude : position.coords.longitude}, 
            // }); 
        }, 
        // 取得失敗した場合 
        function(error) { 
          switch(error.code) { 
            case 1: //PERMISSION_DENIED 
              alert("位置情報の利用が許可されていません"); 
              break; 
            case 2: //POSITION_UNAVAILABLE 
              alert("現在位置が取得できませんでした"); 
              break; 
            case 3: //TIMEOUT 
              alert("タイムアウトになりました"); 
              break; 
            default: 
              alert("その他のエラー(エラーコード:"+error.code+")"); 
              break; 
          } 
        } 
      ); 
    } 
  </script> 
 
途中のajaxの記述は別に無くて大丈夫です。

興味本位でajaxとwindow.location.hrefを比較してました。(結果は後者の方が記述が少なくてわかりやすいから採用)

window.location.href の部分は書き方は参考までに書きますが、適宜修正してください。

モデル.rb
window.location.href = "渡すURL?latitude="+position.coords.latitude+"&longitude="+position.coords.longitude 
 
渡すURLはコントローラーのアクションを呼び出します。


検索

先ほど記述したURLからコントローラのアクションを呼び出します。

ポイントはlatitudeとlongitudeをfloat型で受け取っている所です。
@locationsに半径500m以内にある施設(自分の場合は飲食店)を配列で入れます。

.within_boxはgeocorderのメソッドで

Model.within_box(マイル, 緯度, 経度) 
という使い方が出来ます。これで半径マイルのが出せます。

ちなみに0.310686はメートルに直すと500mです。

コントローラ
def search_location 
        latitude = params[:latitude].to_f 
        longitude = params[:longitude].to_f 
        @locations = Shop.within_box(0.310686, latitude, longitude) 
end 


終わり

初めて記事を書いてみましたが恐ろしいほど復習になりました。

間違っている箇所もあるとは思いますが優しく教えてください!

ありがとうございました。

コメント

このブログの人気の投稿

投稿時間:2021-06-17 22:08:45 RSSフィード2021-06-17 22:00 分まとめ(2089件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)