💬

Rails + PostgleSQLでカラムのデータ型を変更したい

2024/12/06に公開

はじめに

エンジニア転職を目指しRuby on Railsを中心に学習中の初学者です。
備忘録として、躓いたことやケアレスミスも含め投稿します!誤っている箇所などありましたらご指摘いただけると幸いです

対象読者

  • Ruby on Rails初学者

記事概要

例:t.string "age"

誤ってinteger型にするべきカラムをstring型でmigrateしてしまった経験ありませんか?

Railsでデータベースのカラムのデータ型を変更したい場合は、以下の手順を実行します。

  1. マイグレーションファイルの作成:

    マイグレーションを作成して、ageカラムのデータ型を変更します。例えば、stringからintegerに変更する場合は、以下のコマンドをターミナルで実行します。

    
    rails generate migration ChangeAgeToInteger 
    #`ChangeAgeToInteger` 部分はmigrationファイルをどのように修正するのかわかる名前ならなんでもOK!
    
    
  2. マイグレーションファイルの編集:

    作成されたマイグレーションファイルに、データ型変更のコードを追加します。ファイルはdb/migrate/ディレクトリに生成されます。

    ruby
    コードをコピーする
    class ChangeChildAgeToInteger < ActiveRecord::Migration[6.1]
      def change
        change_column :your_table_name, :age, :integer
      end
    end
    
    

    your_table_nameを、ageカラムが含まれるテーブルの名前に置き換えてください。

  3. マイグレーションの実行:

    マイグレーションを実行して、データベースに変更を反映させます。以下のコマンドを実行します。

    
    rails db:migrate
    

これで、ageカラムのデータ型が変更されます。

注意点:

  • データ型を変更する際は、既存データの互換性やデータ変換が必要かどうかを確認してください。
  • 重要なデータを取り扱う場合は、事前にデータベースのバックアップを取ることをお勧めします。

上記方法で下記のエラー経験ありませんか?


== 20240801094618 ChangeChildAgeToInteger: migrating ==========================
-- change_column(:users, :age, :integer)
bin/rails aborted!
StandardError: An error has occurred, this and all later migrations canceled: (StandardError)

PG::DatatypeMismatch: ERROR:  column "age" cannot be cast automatically to type integer
HINT:  You might need to specify "USING age::integer".
/myapp/db/migrate/20240801094618_change_age_to_integer.rb:3:in change'

Caused by:
ActiveRecord::StatementInvalid: PG::DatatypeMismatch: ERROR:  column "child_age" cannot be cast automatically to type integer (ActiveRecord::StatementInvalid)
HINT:  You might need to specify "USING age::integer".
/myapp/db/migrate/20240801094618_change_age_to_integer.rb:3:in change'

Caused by:
PG::DatatypeMismatch: ERROR:  column "age" cannot be cast automatically to type integer (PG::DatatypeMismatch)
HINT:  You might need to specify "USING age::integer".
/myapp/db/migrate/20240801094618_change_age_to_integer.rb:3:in change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

このエラーは、PostgreSQLがageカラムをstring型からinteger型に自動的に変換できないために発生しています。

具体的には、文字列(string)を数値(integer)に変換しようとするときに、文字列の内容によっては数値に変換できないデータが保存されてることが要因です。

エラーメッセージに記載されている「USING age::integer」は、PostgreSQLに対して、特定の方法で型を変換するように指示するヒントです。

解決方法

エラーメッセージの通り、USING句を使ってカラムのデータ型を変換する方法を指定します。

  1. マイグレーションファイルの修正:

    既存のマイグレーションファイルに、USING句を追加して、データ型の変換方法を指定します。例えば、次のようにマイグレーションを変更します。

    
    class ChangeChildAgeToInteger < ActiveRecord::Migration[6.1]
      def change
        change_column :users, :child_age, 'integer USING CAST(child_age AS integer)'
      end
    end
    
    

    ここで、CAST(child_age AS integer)は、PostgreSQLにchild_ageの値を整数に変換するように指示する部分です。

  2. マイグレーションの再実行:

    修正したマイグレーションを再実行します。最初に、現在のマイグレーションをロールバックし、再度マイグレーションを適用します。

    
    rails db:rollback STEP=1 #STEP=数字の数字は戻る分の数字を入力
    rails db:migrate
    
    

この変更により、ageカラムのデータ型がstringからintegerに正しく変換されるはずです。

注意点

  • もしageカラムに数値に変換できない文字列データ(例: "ten"など)が含まれている場合、エラーが発生する可能性があります。その場合は、データを手動で修正するか、変換できないデータを削除する必要がありますのでご注意を…。
  • データ型の変更は、アプリケーションの動作に影響を与える可能性があるため、事前にデータのバックアップを取ることをお勧めします。

Discussion