namespace :db do desc "Generate SQL to convert all tables and columns to utf8mb4" task :utf8_migration => :environment do target_charset = "utf8mb4" target_collation = "utf8mb4_unicode_520_ci" db = ApplicationRecord.connection # Don't mess with ActiveRecord's internal tables! tables = db.tables.reject { |t| t.start_with? "ar_internal_" } ups = [] downs = [] tables.sort.each do |table| # If the table's default charset/collation doesn't match our goal, we'll # modify it! db.table_options(table) => {charset:, collation:} if charset != target_charset || collation != target_collation ups << "ALTER TABLE #{table} CONVERT TO CHARACTER SET " + "#{target_charset} COLLATE #{target_collation}" downs << "ALTER TABLE #{table} CONVERT TO CHARACTER SET " + "#{charset} COLLATE #{collation}" end end puts <<~MIGRATION_RB reversible do |direction| direction.up do #{sql_as_ruby(ups).indent(2, "\t")} end direction.down do #{sql_as_ruby(downs).indent(2, "\t")} end end MIGRATION_RB end end def sql_as_ruby(statements) statements.map do |sql| <<~EXECUTE_RB execute <<-SQL #{sql} SQL EXECUTE_RB end.join("") end