web-dev-qa-db-ja.com

RailsマイグレーションでNULL可能列をNULL不可に変更するにはどうすればよいですか?

以前の移行で日付列を作成し、null許容に設定しました。次に、null不可に変更します。そのデータベースにヌル行があると仮定して、これを行うにはどうすればよいですか?それらが現在nullである場合、これらの列をTime.nowに設定しても構いません。

176
Kevin Pang

移行で行う場合は、おそらく次のようにすることができます。

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false
189
DanneManne

Rails 4では、これはより良い(DRYer)ソリューションです。

change_column_null :my_models, :date_column, false

その列にNULL値を持つレコードが存在しないようにするには、NULL値を持つレコードに使用するデフォルト値である4番目のパラメーターを渡すことができます。

change_column_null :my_models, :date_column, false, Time.now
145
mrbrdo

Rails 4(その他のRails 4の回答には問題があります):

def change
  change_column_null(:users, :admin, false, <put a default value here> )
  # change_column(:users, :admin, :string, :default => "")
end

NULLを許可しないようにNULL値を含む列を変更すると、問題が発生します。これはまさに開発セットアップで問題なく動作し、LIVE本番環境にデプロイしようとするとクラッシュするタイプのコードです。最初にNULL値を有効な値に変更し、thenでNULLを禁止する必要があります。 change_column_nullの4番目の値はまさにそれを行います。詳細については documentation をご覧ください。

また、新しいオブジェクトを作成するたびにフィールドの値を指定する必要がないように、通常はフィールドにデフォルト値を設定することを好みます。それを行うためにコメントアウトされたコードも含めました。

66
Rick Smith

change_column値を持つ:default =>ステートメントを持つ移行を作成します。

change_column :my_table, :my_column, :integer, :default => 0, :null => false

参照: change_column

データベースエンジンによっては、change_column_nullを使用する必要がある場合があります

32
jessecurry

Rails 4:

def change
  change_column_null(:users, :admin, false )
end
11
piratebroadcast

Rails 4.02 +では、 docs に従って、2つの引数を持つupdate_allのようなメソッドはありません。代わりに、次のコードを使用できます。

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false
3
jmarceli

既存のレコードがある場合、add_timestampsとnull:falseを使用できないため、解決策は次のとおりです。

def change
  add_timestamps(:buttons, null: true)

  Button.find_each { |b| b.update(created_at: Time.zone.now, updated_at: Time.zone.now) }

  change_column_null(:buttons, :created_at, false)
  change_column_null(:buttons, :updated_at, false)
end
2