From fdd7806071acd1028d3d659734f23cc4d84369ed Mon Sep 17 00:00:00 2001 From: Andrew Kvalheim Date: Mon, 11 May 2020 21:55:36 -0700 Subject: [PATCH] Work around bug in migrations to non-null columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running migration 20170705075039 followed by 20170715131706, the latter fails due to lingering null values in a newly non-null column— Mysql2::Error: Invalid use of NULL value: ALTER TABLE `tracks` CHANGE `state` `state` varchar(255) DEFAULT 'new' NOT NULL db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb:17:in `change' —despite having apparently converted any existing null values prior to changing the column type. Investigation reveals that actually the attempted conversion has had no effect, and that this can be resolved by clearing ActiveRecord internal caches between migrations: connection.schema_cache.clear_data_source_cache! 'tracks' The same problem also affects running 20170705075039 followed by 20170720134353, but in that case it leads to silent data corruption as `change_column_null` automatically converts any lingering null values. This commit 1) clears ActiveRecord internal caches at the beginning of each affected migration, and 2) replaces `change_column_null` with `change_column` to reflect that no automatic conversion is intended. --- ...5131706_make_track_state_not_null_and_add_default_value.rb | 2 ++ db/migrate/20170720134353_make_track_cfp_active_not_null.rb | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb b/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb index 2d8d9b2d..6382df7b 100644 --- a/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb +++ b/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb @@ -6,6 +6,8 @@ class MakeTrackStateNotNullAndAddDefaultValue < ActiveRecord::Migration end def change + TmpTrack.reset_column_information + TmpTrack.where(state: nil).each do |track| track.state = 'confirmed' track.save! diff --git a/db/migrate/20170720134353_make_track_cfp_active_not_null.rb b/db/migrate/20170720134353_make_track_cfp_active_not_null.rb index b96d84fe..916ede43 100644 --- a/db/migrate/20170720134353_make_track_cfp_active_not_null.rb +++ b/db/migrate/20170720134353_make_track_cfp_active_not_null.rb @@ -6,11 +6,13 @@ class MakeTrackCfpActiveNotNull < ActiveRecord::Migration end def change + TmpTrack.reset_column_information + TmpTrack.where(cfp_active: nil).each do |track| track.cfp_active = true track.save! end - change_column_null :tracks, :cfp_active, false + change_column :tracks, :cfp_active, :boolean, null: false, default: false end end