1

MySQL 5.7 began failing old migrations that set a default for columns of type text.

After editing the migration, dropping the development db and re-running all migrations, all worked fine in development.

For production:

1. Is my below understanding correct? Is this the main and/or only issue (besides editing old migrations being frowned upon)

The issue to look out for is that since you can't drop a production db, these migrations will not be run and not reflected in db/schema.rb. As a result, your code will be error prone because it was written to work with a slightly different schema in development.

2. My solution is to essentially force the migration to re-run by calling its up method in a new migration. (See below code). Is this a reasonable solution? ie. Will it work in all cases (no critical downfalls).

This is the original migration, made years ago in Rails 2

class AddZipWarpableResHistory < ActiveRecord::Migration[5.2]
  def self.up
    add_column :warpables, :history, :text, :default => "", :null => false
    add_column :warpables, :cm_per_pixel, :float, :default => 0, :null => false

    Warpable.find(:all).each do |w|
      r = w.get_cm_per_pixel
      w.cm_per_pixel = r if r != nil
      w.save
    end

  end

  def self.down
    remove_column :warpables, :history
    remove_column :warpables, :cm_per_pixel
  end
end

after edits (only including the edited lines below) in Rails 5

class AddZipWarpableResHistory < ActiveRecord::Migration[5.2]
  def self.up
    add_column :warpables, :history, :text, :null => false
    
    Warpable.all.each do |w|  # edited this bc find(:all) was broken as well
      r = w.get_cm_per_pixel
      w.cm_per_pixel = r if r != nil
      w.save
    end
  end
end

new migration to ensure it works in production:

  • Note that none of the changes in that migration have any subsequent changes in other migrations before this one to account for
require_relative '20111005211631_add_zip_warpable_res_history'

class EnsureNoWarpableCorruption < ActiveRecord::Migration[5.2]
  def self.up
    AddZipWarpableResHistory.down
    AddZipWarpableResHistory.up

    msg = 'MySQL 5.7 began throwing errors on migrations that set a default for columns of type text.' + 
          'We edited that migration and rerun it here to ensure no data corruption in production'
    
    change_table_comment(:warpables, msg)
  end

  def self.down
    raise ActiveRecord::IrreversibleMigration
  end
end
  1. Would just editing the production DB manually in MySQL before merging this be an alternative solution if the model code wasn't updated as well?
  • MySQL doesn't support transactional migrations. Is this the simple solution when working with other databases?

Notes
  • I didn't execute SQL directly because then we would probably need to start storing db/structure.sql instead of db/schema.rb.

  • I didn't try to fix any model code or other logic.

user7247147
  • 1,045
  • 1
  • 10
  • 24
  • Why do you need to run old migrations in the development? There should be no reason to do that. – edariedl Sep 07 '19 at 06:45
  • @edariedl in this case was upgrading from Rails 4 -> Rails 5, which resulted in changes to `ar_internal_metadata` and `db:migrate` and `db:drop` commands threw an error. The only way to fix it was to drop the database in MySQL, then re-run all migrations to generate new `schema.rb` – user7247147 Sep 07 '19 at 06:54
  • 1
    Interesting I don't remember that we would have similar problems with the upgrade to rails 5. Everything worked as expected without dropping the database, regenerating `schema.rb`, etc.. I would not use the old migration again. Rather use just `change_column` to remove the default, it is safer and you don't lose any data. – edariedl Sep 07 '19 at 07:05
  • @edariedl The issue is written about here: https://stackoverflow.com/questions/45925383/activerecordnoenvironmentinschemaerror#4965188. That doesn't work because when a migration fails the process aborts. – user7247147 Sep 07 '19 at 07:11
  • 2
    have you tried `rake db:create db:schema:load` it doesn't run the migrations but loads your DB from the `schema.rb` file directly. It is much faster and it doesn't execute old migrations. – edariedl Sep 07 '19 at 07:15
  • Just went back to `main` to try this - `db:schema:load` also throws the error from the stackoverflow post (`ActiveRecord::NoEnvironmentInSchemaError:`). So the issue is the schema is "broken". And the migrations are broken as far as MySQL is concerned, and to generate a new schema you need to run migrations – user7247147 Sep 07 '19 at 07:37
  • 1
    got mixed up in my 1st comment! `$ rails db:migrate` is all thats needed to update the metadata, and this doesn't work bc of the MySQL error not Rails. So that is why this is not a typical problem in the upgrade. Any schema related commands don't work after the upgrade until this command is run – user7247147 Sep 07 '19 at 07:50
  • I would not recommend your 3rd option. Are you able to clone your prod db and stack to a local mirror or staging environment? The last thing you want to do is break your production environment. – lacostenycoder Sep 07 '19 at 11:04
  • @lacostenycoder yes everything is backed up! I was looking for advise from developers with experience with this about the best way to do this.. .but I am realizing now that this is a very 1 off case – user7247147 Sep 09 '19 at 20:46
  • answer on this question was updated, not sure if will help you https://stackoverflow.com/questions/45925383/activerecordnoenvironmentinschemaerror – lacostenycoder Sep 10 '19 at 01:48
  • thank you yes that answers how to do it without messing with migrations. So if migrations are outdated (failing and aborting) it's recommended to just leave them? Is that considered a sort of technical debt? – user7247147 Sep 10 '19 at 05:06

0 Answers0