MySQLで以下のようなカラムがあったとして
t.integer "foo", limit: 4, default: 0, null: false #`foo` int(11) NOT NULL DEFAULT '0',
以下のようなマイグレーションを実行したとすると
change_column("articles", "foo", :integer, null: false)
実行されるALTER文はこうなる。
ALTER TABLE `articles` CHANGE `foo` `foo` int(11) DEFAULT 0 NOT NULL
明示的にdefault: nil
を設定すると…
change_column("articles", "foo", :integer, null: false, default: false)
ALTER TABLE `articles` CHANGE `foo` `foo` int(11) DEFAULT 0 NOT NULL
DEFAULTを削除するためには「null: true
」または「null
を付けない」ようにする必要がある。
change_column("articles", "foo", :integer, null: true, default: nil)
ALTER TABLE `articles` CHANGE `foo` `foo` int(11) DEFAULT NULL
ActiveRecordのコード
ActiveRecordのコードでは明示的にdefaultが付けられていない場合、既存のカラムの値を使うようになっている。
def change_column_sql(table_name, column_name, type, options = {}) column = column_for(table_name, column_name) unless options_include_default?(options) options[:default] = column.default end
options_include_default?
のコードは以下の通り。
def options_include_default?(options) options.include?(:default) && !(options[:null] == false && options[:default].nil?) end
「options
に:default
が含まれていて」かつ「options[:null]
がfalse
ではない」とき、:default
が含まれていると見なす。
change_columnの動作としては正しい気がするが、NULL DEFAULT 0
のカラムをNOT NULL
に一気に変更することができないと思うけど、そういうパターンは少ないからいいのだろうか、、、
default: nil
について
ActiveRecordのコードを読むとdefault: nil
は、null:false
以外のとき有効なよう。
def add_column_options!(sql, options) sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options) # must explicitly check for :null to allow change_column to work on migrations if options[:null] == false
ridgepoleでの扱い
「未定義はnil」としました。
が、null: false
以外のときの動作が気になる、、、
if not opts.has_key?(:default) opts[:default] = nil end