web-dev-qa-db-ja.com

Railsにデフォルトがないことによるchange_column_defaultの可逆移行

Railsはアクティブなレコードの移行をガイドしています は、

change_column_default :products, :approved, from: true, to: false

Railsにはchangeメソッドがあります。これは次のようになります。

change_column_default :people, :height, from: nil, to: 0

デフォルトがないことからゼロのデフォルトにすることを目的としています。

しかし、ロールバックしようとすると、

ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

Rails a fromtoを与えることを考えると、なぜそれを受け入れないのですか?

私はRails 4.2.0を使用しています。

18
Andrew Grimm

fromおよびtoの使用は 追加 in Rails 5+

質問にリンクされているガイドはEdge Rails用であり、リリースされたバージョンのRails用ではありません。

change_column_defaultのリバーシブル構文は、プルリクエストの結果 20018 です。プルリクエストでは、Edge RailsのRailsガイドも更新されました。

activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rbから:

-      def change_column_default(table_name, column_name, default)
+      # Passing a hash containing +:from+ and +:to+ will make this change
+      # reversible in migration:
+      #
+      #   change_column_default(:posts, :state, from: nil, to: "draft")
+      #
+      def change_column_default(table_name, column_name, default_or_changes)

プルリクエストは2015年6月27日に行われ、2015年8月1日にリリースされたRailsのどのバージョンよりも新しいものです。

Rails 4.2. のマイグレーション)のドキュメントは、リバーシブル構文がまだ利用できないという事実を反映しています:

change_column_default :products, :approved, false
13
Andrew Grimm

mysqlをアダプターとして使用している場合、このリンクに従って http://apidock.com/Rails/ActiveRecord/ConnectionAdapters/AbstractMysqlAdapter/change_column_defaultchange_column_default移行は次のように実行されます

def change_column_default(table_name, column_name, default) #:nodoc:
 column = column_for(table_name, column_name)
 change_column table_name, column_name, column.sql_type, :default => default
end

ご覧のように、change_columnを呼び出すと、それ自体がchange_column_defaultを呼び出します。また、このリンクによると http://edgeguides.rubyonrails.org/active_record_migrations.htmlchange_column移行は元に戻せません。

これは、ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigrationを取得する理由を示しています

したがって、change_column_defaultを使用して移行を実行する場合は、def updef downを追加する必要があります。

Change_column_default内で既に呼び出されているため、change_columnを使用することをお勧めします。

def up
 change_column :people, :height, :integer, default: 0
end

def down
 change_column :people, :height, :integer, default: nil
end
17
Athar

2016年10月現在、この機能(to:およびfrom: ために change_column_defaultをリバーシブルにする)が5.xブランチで利用可能になりました。残念ながら4.2.x以下では利用できません。 :(

検証:git tag --contains f9c841927ac3d1daea2a9cebf08b18e844e5eec5 Railsプロジェクト。

1
hajpoj

移行ファイルに問題がある場合は、移行をこの形式に変更してください。

change_column_default :table_name, :column_name, from: nil, to: "something"
0
Jin Lim

いくつかのポイントを追加するだけです。 Railsバージョンがリバーシブルなchange_column_defaultをサポートしていない場合は、問題を回避する1つの方法は次のとおりです。

def change
    # If your dataset is small, just cache in memory, if large, consider file dump here:
    cache = Table.all
    # Full column def important for reversibility
    remove_column :table, :column, :type, { config_hash }
    # Re-add the column with new default:
    add_column  :table, :column, :type, { config_hash, default: 0 }
    # Now update the data with cached records (there might be more efficient ways, of course):
    cache.each do |rec|
        Table.find(rec.id).update(column: rec.column)
    end
end
0
Vlad