LoginSignup
0
0

More than 1 year has passed since last update.

2つのテーブルを1対多の関係になるようadd_referenceするとSQLite3::SQLException: Cannot add a NOT NULL column with default value NULL

Last updated at Posted at 2021-05-28

「現場で使えるRuby on Rails5速習実践ガイド」を進めていて、P.169の マイグレーションを実行すると以下のエラーが発生しました。

/taskleaf:$ bin/rails db:migrate
== 20210524174653 AddUserIdToTasks: migrating =================================
-- execute("DELETE FROM tasks;")
   -> 0.0009s
-- add_reference(:tasks, :user, {:null=>false, :index=>true})
rails 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
...
(省略)

試したこと

どのマイグレーションファイルまで実行されたかを確認したくて調べたところ、以下のコマンドで確認できそうでした。

bundle exec rake db:migrate:status

実行すると

/taskleaf:$ bundle exec rake db:migrate:status

database: /Users/{ユーザID}/workspace/runteq/genba_rails/taskleaf/db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20210517160153  Create tasks
   up     20210521153755  Change task name not null
   up     20210521160018  Change tasks name limit30
   up     20210521172340  Create users
   up     20210521175601  Add admin to users
  down    20210524174653  Add user id to tasks

どうやら直近(P.169)で作成したマイグレーションファイルが実行できず、ロールバックされていそうです。

エラーログに戻ると、

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

英語が目にくるのでDeepL翻訳にかけたところ

SQLite3::SQLException: デフォルト値がNULLのNOT NULLカラムを追加できません: ALTER TABLE "Tasks" ADD "user_id" integer NOT NULL

らしいです。

原因

書籍ではDBにPostgreSQLを指定してアプリを立ち上げていましたが、SQLiteで進めていたことが原因のようです。

当然である.NOT NULL な column なのに default を指定しなければ,もし行が既に存在した場合その
column (今回は price) が NULL にならざるを得ないではないか.

しかし PostgreSQL だとこれが通るのである.先のコマンドを以下のように変えて見ると分かる.

解消した方法

マイグレーションファイルを以下のように修正しました。
add_referenceを実行したあと
後からnot null制約をつける(change_column_null)ことで正常にマイグレーションが実行できました。
(コメントアウト行がエラー発生した書籍どおりのコードです。)

class AddUserIdToTasks < ActiveRecord::Migration[5.2]
  def up
    execute 'DELETE FROM tasks;'
    # add_reference :tasks, :user, null: false, index: true
    add_reference :tasks, :user, index: true
    change_column_null :tasks, :user_id, false
  end

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

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0