The change_column method for rails migrations support casting with a custom SQL statement. This allows us to change a column type and keep the former content as the new type. This way, we can for example prepare an address number column to hold German address numbers, which can contain letters:
Example (in most cases not a good idea!)
class ChangeAnIntegerColumnToString < ActiveRecord::Migration[6.1]
  def up
    change_column :users, :address_number, 'varchar USING CAST(rating AS varchar)'
  end
  def down
    change_column :users, :address_number, 'int USING CAST(rating AS int)'
  end
end
Warning
This migration's rollback strategy will fail, if any existing entry can't be casted. This is likely to happen, if you migrate the previous example, insert an entry with the value
12aand later try to rollback.
The safe way
BE CAREFUL with this method, you should really be sure that it's okay to use an irreversible migration! if you know that no one will ever rollback your migration, you can define the down method as follows:
  def down
    raise ActiveRecord::IrreversibleMigration
  end
Info
The
ActiveRecord::IrreversibleMigrationerror states that a migration can't be rolled back due to data loss.
The safest way
The safest (but also most expensive) way would be to handle the cast yourself:
class ChangeAnIntegerColumnToString < ActiveRecord::Migration[6.1]
  class User < ActiveRecord::Base; end
  
  def up
    change_column :users, :address_number, 'varchar USING CAST(rating AS varchar)'
  end
  def down
    rename_column :users, :address_number, :address_number_string
    add_column :users, :address_number, :integer
    User.reset_column_information
    
    User.find_each do |user|
      # your cast here, e. g.:
      sanitized_address_number = user.address_number_string.remove(/\D/)
      user.update!(address_number: sanitized_address_number)
    end
    
    remove_column :users, :address_number_string
  end
end