変更列のRailsマイグレーション


327

script/generate migration add_fieldname_to_tablename fieldname:datatype新しい列をモデルに追加するための構文があります。

同じ行に、列のデータ型を変更するためのスクリプト/生成がありますか?それとも、SQLを直接バニラマイグレーションに書き込む必要がありますか?

私はから列を変更したいdatetimedate

回答:


549

これでうまくいくと思います。

change_column :table_name, :column_name, :date

13
@b_ayan:私の知る限り、移行名の魔法の単語は「追加」と「削除」だけです。
Alex Korban

1
並べ替えのレールはここではありませんが、…私は答えを理解していますが、この回答のコメントは理解していません。明確化が評価されました:)
アランH.11年

7
マイグレーションを作成するときに、名前を付けます(上記の質問ではadd_fieldname_to_tablenameなど)。「追加」または「削除」で始まる場合、移行には列を追加または削除するコードが自動的に入力されるため、そのコードを自分で作成する手間が省けます。
Alex Korban、2011年

6
また、あなたがいつも交換する必要があります心の中で価値のベアリングだchange別々とアクションupdown同様に、アクションをchange_column不可逆的な移行があると、あなたがロールバックする必要がある場合、エラーが発生します。
DaveStephens、2015

1
@QPaysTaxes upには、列の変更元と変更先を含める必要があり、downには、その変更を元に戻す方法を含める必要があります。
DaveStephens、2016年

98

テーブル内で変更する列が複数ある場合は、ブロックを使用することもできます。

例:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

詳細については、TableクラスのAPIドキュメントを参照してください。


88

コマンドラインから移行を作成してこれをすべて実行できるかどうかはわかりませんが、新しい移行を作成してから、移行を編集してこのタスクを実行できます。

tablenameがテーブルの名前で、fieldnameがフィールドの名前で、日時から日付に変更したい場合は、移行を作成してこれを行うことができます。

以下を使用して新しい移行を作成できます。

rails g migration change_data_type_for_fieldname

次に、change_tableを使用するように移行を編集します。

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

次に、移行を実行します。

rake db:migrate

32

以前の回答で見つけたように、列のタイプを変更するには3つのステップが必要です。

ステップ1:

次のコードを使用して、新しい移行ファイルを生成します。

rails g migration sample_name_change_column_type

ステップ2:

/db/migrateフォルダーに移動し、作成した移行ファイルを編集します。2つの異なるソリューションがあります。

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end

2。

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

ステップ3:

このコマンドを実行することを忘れないでください:

rake db:migrate

このソリューションをRails 4でテストしましたが、うまく機能します。


1
ステップ2で、最初はrake db:rollbackを実行した後に失敗します
。2

移行ファイルに移動せずに生成し、編集するときにすべてを多かれ少なかれできるようにするRailsの規則はありますか?
BKSpurgeon 2017年

@BKSpurgeonはい、こちらのドキュメントを確認してください:edgeguides.rubyonrails.org/active_record_migrations.html
Aboozar Rajabi 2017年

12

Rails 5を使用

Railsガイドから:

Active Recordがリバースする方法を知らない何かをするマイグレーションに望むならば、あなたは使うことができますreversible

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end

8

マイグレーションを生成するだけです:

rails g migration change_column_to_new_from_table_name

次のように移行を更新します。

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

そして最後に

rake db:migrate

2

移行を使用してデータ型を変更する別の方法

ステップ1: 移行を使用して、エラーが発生したデータ型のフィールド名を削除する必要があります

例:

rails g migration RemoveFieldNameFromTableName field_name:data_type

ここで、フィールドのデータ型を指定することを忘れないでください

ステップ2: 正しいデータ型のフィールドを追加できるようになりました

例:

rails g migration AddFieldNameToTableName field_name:data_type

以上で、テーブルに正しいデータ型フィールドが追加されました。Happyrubyコーディング!!


2

これはすべて、列のデータ型に既存のデータの暗黙的な変換があることを前提としています。既存のデータStringが暗黙的に新しいデータ型に変換できるとしましょうDate

この状況では、データ変換を使用して移行を作成できることを知っていると役立ちます。個人的には、これらをモデルファイルに入れて、すべてのデータベーススキーマが移行されて安定したら削除するのが好きです。

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end

0

デフォルト値を編集する場合に回答を完了するには:

Railsコンソールで:

rails g migration MigrationName

移行中:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

次のようになります:

  def change
    change_column :members, :approved, :boolean, default: true
  end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.