マイグレショーンファイルを作成する際のnull: false


今回はnull: falseオプションについてです。
このオプションはマイグレーションファイルにてカラムを追加する際によく使います。

役割としては、カラムに何もデータを入れなければエラーが出ますよ、というものです。

今回出現したエラー

terminal

rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: Cannot add a NOT NULL column with default value NULL: ALTER TABLE "tasks" ADD "user_id" integer NOT NULL

今回、userテーブルとtaskテーブルを関連づけるために以下のマイグレーションファイルを作成しました。

関係としては、has_many :tasks、belongs_to :userという1対多の関係性です。

xxxxxxxxxxxxxx_add_user_id_to_tasks.rb
class AddUserIdToTasks < ActiveRecord::Migration[5.2]
  def up
    add_reference :tasks, :user, null :false, index: true
  end

  def down
    remove_reference :tasks, :user, index: true
  end
end

として、Taskテーブルにuser_idという外部キーを設置しようとしました。
しかし、何度、マイグレーションファイルを実行してもエラーが出てしまう。

実は以前、同じエラーが出た時にカラムを追加するテーブルにnullなレコードがあったのが原因だったことがありまして、いったん"rails c"で"Task.delete_all"と念の為"User.delete_all"をしてみましたが、一向に改善する気配はありません。

解決方法

解決方法としては、結論からいうと、null制約のオプションはカラム追加と別に行う、というものでした。

と言いますのも、エラー内容からもしかして、null: falseがなければ実行できるのでは、と思いやってみると、やはりできました。

これは、もしかするとMySQLの特性なのかもしれません(おそらくですが)。

そして、さらにマイグレーションファイルを追加しました。

xxxxxxxxxxxxxx_change_user_id_to_tasks.rb

class ChangeUserIdToTasks < ActiveRecord::Migration[5.2]
  def change
    change_column :tasks, :user_id, :integer, null: false
  end
end

これで、無事にuser_idにnull制約をつけることができました。

みなさまの参考になれば幸いです。