Rails5.1すでに存在するカラムをmigrationでnot nullにする

2018年4月15日

 

change_column_nullを使う

 

すでに存在するカラムをマイグレーションでnullにするには、change_column_nullを使います。

 

class ChangeLikeCountToPost < ActiveRecord::Migration[5.1]
  def change
    change_column_null :posts, :like_count, null: false, 0
  end
end

 

change_column_nullはDBの定義をnull:オプションで指定した定義に変更するまえに、値がnullのものを第4引数にupdateしたのちにDB定義を変更してくれます。

 

def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
  unless null || default.nil?
    execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
  end

  change_column table_name, column_name, nil, null: null
end

 

change_columnでもDBの定義は変更できますが、このメソッドは問答無用でDBの定義を変更しにいくので、「値がNullのカラムにNotNull制約をつけることはできません」となって怒られます。

 

 change_column_nullはDBのデフォルト値も変更してくれるわけではない

 

下のコードをみると、NotNull制約をつけるついでにDBのデフォルト値も設定してくれそうに見えますが、

 

change_column_null :posts, :like_count, null: false, 0

 

実際は、そこまでやってくれません。第四引数の0はnullの値を置き換える値を指定するだけでデフォルト値を指定しているわけではないことに注意しなければいけません。

そのため、NotNull制約をつけるついでにデフォルト値も設定する場合は、以下のようにする必要があります。

 

class ChangeLikeCountToPost < ActiveRecord::Migration[5.1]
  def change
    change_column_null :posts, :like_count, null: false, 0
    change_column :posts, :like_count, :integer, default: 0
  end
end