Railsで座標を扱うときに嵌ったのでメモ
はじめに
携わっているプロジェクトで座標データを保存する必要がありました。
それに対応するために、migrationの記述だったり、コードでの扱いだったりで、思いのほか嵌ったのでメモしておきます。
座標の桁数
こちらを参考にすると座標は 整数部分 3桁、小数点以下 8桁 あれば 誤差が 1.11mm 以内に抑えられるらしいです。
今回は
- そこまで厳密にやる必要もない
- Google Map で一番拡大して “この場所について” で取得できる座標が整数 3桁、 小数点以下 6桁
なので、今回は 整数3桁、小数点以下 6桁。 (誤差 0.111 m (約11cm)) 合計9桁で保存することにしました。
migration
Railsのmigrationのカラム型で小数点を扱うことができるのは float型 と decimal型 になります。
ここ をみると
float型では7桁までした扱うことしかできないので、 今回の要件をみたせないので decimal型を使うことにしました。
class CreatePoints < ActiveRecord::Migration def change create_table :points do |t| ... t.decimal :latitude ... end end end
このような感じで decimal型
で指定してあげて完璧!!
と思ったら甘かった。
decimal型は自分で桁数と小数点の位置を指定しないとデフォルトの小数点以下0桁 になってしまいます。
ですので
t.decimal :latitude, :precision => 9, :scale => 6
このような記述になります。
precision
, scale
は decimal型
のオプションで
- precision: 桁数
- scale: 少数点以下桁数
となります。 今回の設定だと、上記で述べたように 全体で9桁、少数点以下 6桁 となります。
ポイント(?)
モデルから持ってきてそのまま使おうとすると
puts Point.latitude => #<BigDecimal:7f80bfb53b40,'0.139766043E3',18(18)>
となるので、
puts Point.latitude.to_f => 139.766043
表示やAPIとして渡したい時は .to_f するのを忘れないようにしましょう。
最後に
普段は 小数点を扱う時は float でことたりてたので、色々しらべました。
最初、deciaml の precision オプションは整数部分だと勘違いして
t.decimal :latitude, :precision => 3, :scale => 6
と記述してエラーで怒られたのは、今となっては懐かしい思い出です。
参考URL
リア充爆発日記: Railsのmigrationで緯度経度をdecimalで設定する