ActiveRecordエラー

ActiveRecord::StatementInvalid
SQLite3::SQLException: no such column: tasks.user_id:

error文に書いてあるとおりtasksテーブルにuser_idカラムがないというエラーである。 データベース上でUserとTaskを紐付ける際に発生した。 まず、ジェネレータでマイグレーションを作成し、

$rails g migration AddUserIdToTasks 

マイグレーションファイルを以下のように編集しマイグレーションを実行した。

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

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

$bin/rails db:migrate

データベースの状態を確認したところ、マイグレーションを実行したにもかかわらず、データベースにuser_idカラムはつくられていないことがわかった。

#データベースへ接続
$rails db
=>SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.
#データベースの一覧を確認
sqlite>.database
#テーブル一覧を取得
sqlite>.tables 
ar_internal_metadata  tasks               
schema_migrations     users               
#テーブルの中のカラムを確認(今回はtasksテーブル)
sqlite> PRAGMA TABLE_INFO(tasks);
0|id|integer|1||1
1|name|varchar|1||0
2|description|text|0|NULL|0
3|created_at|datetime|1||0
4|updated_at|datetime|1||0
sqlite> .exit

結論

ジェネレータの書き方が間違っていた。マイグレーションファイルにchangeメソッドがなかった。書籍では、bin/rails g migration AddUserIdToTasksで実行しているが、 「rails g migration Addカラム名Toテーブル名 カラム名:カラムのデータ型」このように、カラム名とカラムのデータ型を追加したら Tasksテーブルにuser_idカラムを追加することができた。マイグレーションをやり直すために、最初に作成したファイルを削除する必要がある。

#まず、ステータスを確認する。
$rails db:migrate:status
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20210323195016  Create tasks
   up     20210329092418  Change tasks name not null
   up     20210329175420  Create users
   up     20210329190039  Add admin to users
  down    20210331174646  Add user id to tasks

#upの場合、「$bin/rails db:migrate:down VERSION=migration_file_id」を実行し、downにする。
#downは、まだデータベースへ反映されていないので、削除しても問題ない。削除を実行。
$rm db/migrate/20210331174646_add_user_id_to_tasks.rb

#削除できたかステータスを確認。
$rails db:migrate:status
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20210323195016  Create tasks
   up     20210329092418  Change tasks name not null
   up     20210329175420  Create users
   up     20210329190039  Add admin to users

削除が確認できたらマイグレーションを「rails g migration Addカラム名Toテーブル名 カラム名:カラムのデータ型」で作成。

$bin/rails g migration AddUserIdToTasks user_id:integer
Running via Spring preloader in process 65692
      invoke  active_record
      create    db/migrate/20210401072016_add_user_id_to_tasks.rb

マイグレーションファイルを以下のように編集し、マイグレーションを実行。 マイグレーションファイルでは、changeメソッドの中でテーブルが作成される。

class AddUserIdToTasks < ActiveRecord::Migration[5.2]
  def change
    add_column :tasks, :user_id, :integer
  end

  def up
    execute 'DELETE FROM tasks;'
    add_reference :tasks, :user, null: false, index: true
  end

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

$bin/rails db:migrate
== 20210401072016 AddUserIdToTasks: migrating =================================
-- add_column(:tasks, :user_id, :integer)
   -> 0.0010s
== 20210401072016 AddUserIdToTasks: migrated (0.0011s) ========================

#ステータスを確認
$bin/rails db:migrate:status
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20210323195016  Create tasks
   up     20210329092418  Change tasks name not null
   up     20210329175420  Create users
   up     20210329190039  Add admin to users
   up     20210401072016  Add user id to tasks

user_idカラムが作成されているかデータベースを確認。

$rails db
SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.

sqlite> .databases
sqlite> .tables
ar_internal_metadata  tasks               
schema_migrations     users               

sqlite> PRAGMA TABLE_INFO(tasks);
0|id|integer|1||1
1|name|varchar|1||0
2|description|text|0|NULL|0
3|created_at|datetime|1||0
4|updated_at|datetime|1||0
5|user_id|integer|0||0

sqlite> .exit

無事にuser_idカラムが作成され、解決。