注記
この記事の投稿者は初学者であり、自身の学習の備忘録目的で記事投稿を行なっております。
情報の正確さには最大限注意をしておりますが、もし誤り等がございましたらお知らせいただけますと幸いです。
ご覧いただきありがとうございます!
Ito と申します!
Ruby on Rails初学者です。
RailsでのWebアプリを作成中、データベースにテーブルを作成した際に、設定するデータ型を間違えてしまいました。
それ自体は「あるある」だと思うのですが、migration
ファイルを作成してデータ型を変更しようとした際にほんのちょびっとだけハマってしまったので備忘録として残します。
動作環境
開発環境
- Rails 7.1.3.2
- サーバー:localhost接続
- データベース:PostgreSQL
エラーの詳細
エラーメッセージ
== 20240401****** ChangeLatAndLngToFloatInSpots: migrating ====================
-- change_column(:spots, :lat, :float)
bin/rails aborted!
StandardError: An error has occurred, this and all later migrations canceled: (StandardError)
PG::DatatypeMismatch: ERROR: column "lat" cannot be cast automatically to type double precision
HINT: You might need to specify "USING lat::double precision".
/Users ... /db/migrate/20240401******_change_lat_and_lng_to_float_in_spots.rb:3:in `change'
Caused by:
ActiveRecord::StatementInvalid: PG::DatatypeMismatch: ERROR: column "lat" cannot be cast automatically to type double precision (ActiveRecord::StatementInvalid)
HINT: You might need to specify "USING lat::double precision".
どんな時に発生したか
1.Railsジェネレータを用いて、lat
(緯度)とlng
(経度)属性を持つSpot
モデルを作成
rails generate model Spot lat:string lng:string
2.lat
カラムとlng
カラムをstring
型からfloat
型に変更するため、Railsジェネレータを用いてマイグレーションファイルを作成する
rails generate migration ChangeLatAndLngToFloatInSpots
3.作成されたマイグレーションファイルの中身を書いていく
class ChangeLatAndLngToFloatInSpots < ActiveRecord::Migration[7.1]
def change
change_column :spots, :lat, :float
change_column :spots, :lng, :float
end
end
4.rails db:migrate
を実行する
5.先ほどのエラーメッセージ
調べた結果
PostgreSQLでは、特定の型から別の型への変更を行う際に、データの解釈が自明でない場合(例えばstring
からfloat
への変更など)、どのように変換するかを明示的に指定する必要があるようです。
エラーメッセージには、
「lat
カラムをdouble precision
(Railsで言うfloat
型に相当する)に自動でキャスト(型変換)できないから、明示的なキャスト方法を指定する必要があるよ」 という意味が込められています。
※PostgreSQLのみ発生するのかは、不明です。
こう解決した
次のようにマイグレーションファイルを書き換えてからrails db:migrate
を実行することで、無事にlat
カラムとlng
カラムの型をfloat
型に変更することができました。
class ChangeLatAndLngToFloatInSpots < ActiveRecord::Migration[7.1]
def up
change_column :spots, :lat, 'float USING CAST(lat AS float)'
change_column :spots, :lng, 'float USING CAST(lng AS float)'
end
def down
change_column :spots, :lat, :string
change_column :spots, :lng, :string
end
end
マイグレーションファイルの中で、change
メソッドでなくup
メソッドとdown
メソッドを使います。(up
に失敗した際に、down
の内容にロールバックするため)
その際、up
メソッド内のchange_column
メソッドと組み合わせてusing
オプションを使用し、明示的にcast
を指示しています。
up/down
メソッドについては、Railsガイドをご参照ください。
3.12 up/downメソッドを使う
振り返り
Railsで開発をしている時は、型についてはほとんど考える機会がないため、複雑ではありませんが新しい体験ができたと思います✨
がしかし、もっと注意深くRailsジェネレーターにコマンドを打ち込んでいれば、こんな面倒なことにはならな買ったので、今後は実行前に見直すようにしたいと思います!