Search code examples
ruby-on-railsrails-activestoragenext-rails

Dual booting when there is a breaking database change


I am upgrading an app from 6.0 to 6.1, using the next_rails dual boot gem. As part of the upgrade I needed to execute rails active_storage:update which adds a service_name to the ActiveStorage::Blob table. When I run my tests with next rspec spec this works fine, but rspec spec fails with tests that use active_storage with messages like

ActiveRecord::NotNullViolation:
        PG::NotNullViolation: ERROR:  null value in column "service_name" violates not-null constraint

Is there a way of adding some conditional code (if Rails::VERSION::MINOR) that detects the version is 6.0 and somehow removes the null constraint for the service_name column.


Solution

  • There are two approaches.

    Migrate down to the version before the update:

    if Rails.version == "6.0.0"
      ActiveRecord::Base.connection.migration_context.migrate(20220816031332)
    else
      ActiveRecord::Base.connection.migration_context.migrate
    end
    
    # or maybe invoke the db:migrate tasks instead
    

    You might need to turn off pending migration check: config.active_record.migration_error = false

    This approach is general and should work with any migration(s).


    The second approach is to call migration helpers manually. This is specific to the problem posed in this question and just changes the columns without updating migration version in the database:

    if Rails.version == "6.0.0"
      ActiveRecord::Migration.change_column_null(:active_storage_blobs, :service_name, true)
    else
      ActiveRecord::Migration.change_column_null(:active_storage_blobs, :service_name, false)
    end
    

    The code can be placed in config/environment.rb after Rails.application.initialize!. If you wish to place it earlier, you would need to establish the connection to the database manually.

    Note that both methods cause persistent changes to the database, e.g. will remain after the tests have run. The changes only affect the database of which ever environment the code is run in e.g. test or development.