Home > Software engineering >  ActiveRecord::UnknownAttributeError when adding passive column
ActiveRecord::UnknownAttributeError when adding passive column

Time:06-12

I'm trying to run this migration, and the goal is to not have any server downtime while adding new columns. Since these columns have no relationships to other tables, exist in the code, or are required, I assumed this would be possible. But, after running the migration I observed UnknownAttributeError's being thrown when instantiating a new instance of the model.

The error:

Controller/existing_table/some_method::ActiveRecord::UnknownAttributeError
/code/app/models/existing_table.rb:40:in `new’

The line from the error:

e = ExistingTable.new(existing_table.attributes.except("id"))

The migration:

class AddTestFieldToExistingTable < ActiveRecord::Migration
  def change
    add_column :existing_table, :test_field, :integer
  end
end

When I go to recreate the issue by opening up a console and executing lines similar as above, I don't get the error. My guess is that there is some attributes cached and we do need to have downtime while running these "passive" migrations.

I wonder if the 'existing_table' is still in memory, doesn't have the 'test_field' attribute, and when creating a new instance of ExistingTable it doesn't know how to assign the field. Since I cannot recreate it without starting a new instance, I would be guessing on an alternative solution of re-writing the ExistingTable constructor.

Is there a way to avoid restarting the rails instance or re-writing this code? Am I on the right track?

CodePudding user response:

I tried to replicate your doubt, and I did not get the error, besides, everything worked as expected.

I am using Rails 7.0.1

First, I started puma:

  rails s -b 0.0.0.0

Then create the migration:

   rails g migration AddPassiveToGiro passive:boolean

The migration looks like this:

   class AddPassiveToGiro < ActiveRecord::Migration[7.0]
     def change
       add_column :giros, :passive, :boolean
     end
   end

On rails console I created a new record:

  Giro.create giro: 'delete me', passive: true

Then I modify the view where I list those records (using haml)

      .list-item-description
        = giro.passive.blank? ? 'not passive' : 'is passive'

And everything worked fine, no errors.

CodePudding user response:

Rails load the tables' columns only once when the Rails server is started.

Depending on your setup and how you run your migration at deployment it might be possible that the server or at least one server instance started before the migration was done. Then that server instance will not see the newly added column until the next server restart.

To be safe you need to make sure that the migration ran successfully before you deploy the code changes using that change. Depending on your server setup that might mean that you need two different deployments: One with the migration and then later another with the code changes.

  • Related