Loading Rails models during migrations can lead to problems during seed
by @mzrnsh
Consider this scenario..
You have a users table, created like this:
You have a users table, created like this:
# Migration 1 class CreateUsers < ActiveRecord::Migration[7.0] def change create_table :users do |t| t.string :email, null: false end end end
Then you decide to add `:name` attribute to your User model, but at this time you already have some User records, so you want to make sure existing ones also get the name
# Migration 2 class AddNameToUsers < ActiveRecord::Migration[7.0] def change add_column :users, :name, :string User.find_each do |user| user.email.split('@').first end end end
But later, you decided to remove the `:name` attribute. Maybe you wanted to add separate fields for first name and last name, or maybe for another reason:
# Migration 3 class RemoveNameFromUsers < ActiveRecord::Migration[7.0] def change remove_column :users, :name, :string end end
At some point, you also took care of the seeds file, so that when a new developer joins the project, they can have some data in their fresh database:
# db/seeds.rb if Rails.env.development? User.create(email: '[email protected]') end
Now that developer joins (or you buy a new computer!) and the app needs to be installed from scratch. The typical db commands are run in the terminal:
rails db:drop db:create db:migrate db:seed
So far so good, right? Wrong! This won't work and `PG::UndefinedColumn` error will be raised (well, if you are using PG as your database, that is).
The reason being, you already loaded the User model in migration #2, and at that point, it had a `:name` attribute. But by the time your db is seeded, the column name is still there, but the column itself is gone, hence the error.
Potential fixes:
- Run `rails db:seed` separately so that environment is reloaded
- Manually reload column names in `seeds.rb` via `User.reset_column_information` before calling the `.create` method.
- Get rid of the old migration files (or edit them), because the data migration in that file was probably a one-off thing, and it is already applied to the production database. And the new dev setting up a new db doesn't have historic data, so data migration isn't needed either.
ChatGPT didn't help me figure this out, but weirdly enough, SO did:
https://stackoverflow.com/questions/44188485/error-when-running-migrate-and-seed-together