1
0

【初学者の教訓】gem Sorceryを使う時の注意点とmigrationについて

Posted at

はじめに

Railsでアプリを作成中、gem sorceryでユーザー認証機能を追加しようとしたときに起きた出来事と、そのときに学んだ教訓です。

結論

  • rails generate sorcery:installを実行するとUserモデルも自動的に作成されるので、すでにUserモデルを作っている場合は要注意
  • 公式をよく読みましょう。
    https://github.com/Sorcery/sorcery

何があった?

Railsで掲示板アプリを作成していました。User、Post、Commentなどのモデルを作成したところで、「そういえばsorceryってgemでログイン機能作れるんだったな〜」と軽い気持ちでgemをbundle installし、rails generate sorcery:installしたところ…

web-1  | == 20240827051328 SorceryCore: migrating ======================================
web-1  | -- create_table(:users)
web-1  | bin/rails aborted!
web-1  | StandardError: An error has occurred, all later migrations canceled: (StandardError)
web-1  | 
web-1  | Mysql2::Error: Table 'users' already exists
web-1  | /myapp/db/migrate/20240827051328_sorcery_core.rb:3:in `change'
web-1  | 
web-1  | Caused by:
web-1  | ActiveRecord::StatementInvalid: Mysql2::Error: Table 'users' already exists (ActiveRecord::StatementInvalid)
web-1  | /myapp/db/migrate/20240827051328_sorcery_core.rb:3:in `change'
web-1  | 
web-1  | Caused by:
web-1  | Mysql2::Error: Table 'users' already exists (Mysql2::Error)
web-1  | /myapp/db/migrate/20240827051328_sorcery_core.rb:3:in `change'
web-1  | Tasks: TOP => db:prepare
web-1  | (See full trace by running task with --trace)
web-1 exited with code 1

「usersテーブルはすでに存在しているためmigrateできませんでした」

え、sorceryてUserモデルも自動で作るの??

→公式に書いてあった〜〜〜

Run the following command to generate the core migration file, the initializer file and the User model class.

$ rails generate sorcery:install
https://github.com/Sorcery/sorcery

きちんと読みましょうね。

そんなわけで、Userモデルをすでに作成した状態でSorceryをインストールしてしまったためにマイグレーションエラーが発生しました。

対処方法

【方針】

最初にusersテーブルを作成したmigrationを取り下げ、Sorceryで作成されたmigrationファイルを採用する

【やったこと】

usersテーブルを作成した時のmigrationを取り下げようとしました。

$ rails db:migrate:down VERSION=usersテーブル作成時のmigrationID

が、他のpostsテーブルなどでusersのforeign keyを設定していたためエラーが発生。

Mysql2::Error: Cannot drop table 'users' referenced by a foreign key constraint 'fk_rails_5b5ddfd518' on table 'posts'.

そこで、関連するテーブルのmigrationを1つずつdownしていき、既存のusersテーブルもdown後、Sorceryのusersテーブルのmigrationをupし、関連するテーブルを再度up。

# 作業前
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20240826063633  Create users
   up     20240826064309  Create posts
   up     20240826064450  Create likes
   up     20240827003449  Create comments
  down    20240827051328  Sorcery core
  
# 作業後
 Status   Migration ID    Migration Name
--------------------------------------------------
  down    20240826063633  Create users
   up     20240826064309  Create posts
   up     20240826064450  Create likes
   up     20240827003449  Create comments
   up     20240827051328  Sorcery core

この時点でlocalhost:3000にアクセスすると、ActiveRecord::PendingMigrationErrorが発生しました。適用されていないmigrationがあるとエラーになるのですね。

よくないとは思いつつ、今回は該当のmigrationファイルを削除して対応しました。

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20240826064309  Create posts
   up     20240826064450  Create likes
   up     20240827003449  Create comments
   up     20240827051328  Sorcery core

migrationのおさらい

migrationのupとdown

下記コマンドを打つとmigrationファイルが作成されます。

$ rails generate migration ファイル名 カラム名:

この時点では、migrationファイルが作成されただけで、DBに適用はされていない(down)状態です。

$ rails g migration AddNameToUser name:string
      invoke  active_record
      create    db/migrate/20240828022300_add_name_to_user.rb
      
$ rails db:migrate:status                    

database: myapp_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20240826064309  Create posts
   up     20240826064450  Create likes
   up     20240827003449  Create comments
   up     20240827051328  Sorcery core
  down    20240828022300  Add name to user

ここでrails db:migrateを実行することでStatusがupになり、migrationが適用されます。

migrationを実行するコマンド

上記の通り、migrationファイルが作成されていても、migrationの状態がupになっていないとDBには適用されません。このup/downを実行するコマンドには例えば以下のようなものがあります。

$ rails db:migrate
# まだ実行されていないchangeまたはupメソッドを日付が古い順から実行していく

$ rails db:rollback
# 直前に行ったマイグレーションをロールバックして取り消す(down状態にする)
$ rails db:rollback STEP=3
# 最後に行った3つのマイグレーションをdown状態にする
$ rails db:migrate:down VERSION=migrationID
# 特定のマイグレーションをdown状態にする
$ rails db:migrate:up VERSION=migrationID
# 特定のマイグレーションをup状態にする

補足

up状態のmigrationファイルを削除してはいけません。←やった人

 $ rails db:migrate:status
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20240826063633  Create users
   up     20240826064309  Create posts
   up     20240826064450  Create likes
   up     20240827003449  Create comments
   up     20240827045550  ********** NO FILE **********

migration up状態でファイルを削除してしまうと、rollbackでmigrationをdownすることもできなくなってしまいます。

$ rails db:rollback      
bin/rails aborted!
ActiveRecord::UnknownMigrationVersionError:  (ActiveRecord::UnknownMigrationVersionError)

No migration with version number 20240827045550.

ファイルを元に戻してロールバックするなどで対処しましょう。

今後気をつけること

  • gemを使う時は、公式をよく読む!
  • 通常migrationファイルを修正したい時は、新規でmigrationファイルを作成して変更を適用する
  • 本来、migrationファイルは更新履歴として残しておくべきものなので、基本削除しない

参考

Active Record マイグレーション - Railsガイド

初心者目線のmigrationまとめ(1)【migration消しちゃった?!】 - Qiita

1
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
1
0