注記
この記事の投稿者は初学者であり、自身の学習の備忘録目的で記事投稿を行なっております。
情報の正確さには最大限注意をしておりますが、もし誤り等がございましたらお知らせいただけますと幸いです。
ご覧いただきありがとうございます!
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ジェネレーターにコマンドを打ち込んでいれば、こんな面倒なことにはならな買ったので、今後は実行前に見直すようにしたいと思います!