Loading Rails models during migrations can lead to problems during seed

by @mzrnsh

Consider this scenario..

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

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|

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

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]')

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:

  1. Run `rails db:seed` separately so that environment is reloaded
  2. Manually reload column names in `seeds.rb` via `User.reset_column_information` before calling the `.create` method.
  3. 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:

Regarding privacy concerns, it's simple - we don't sell your data. In fact, we try to use privacy-focused software/services like Fathom Analytics whenever we use any third-party services.