読者です 読者をやめる 読者になる 読者になる

@Konboi memo

主に技術に関してつらつらと。

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, scaledecimal型 のオプションで

  • 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で設定する