We recently introduced ActiveAdmin to our application to add simple admin functionality during a bigger architectural change. When editing obejcts with a field named country ActiveAdmin relies on the country-select gem to make the selection and internationalization of countries easier.

Problem

country-select stores the countries then nicely in the ISO format, i.e. ‘US’ for United States of America or ’DE’ for Germany. For now we were using german country name even though the app supports different languages. So I needed to migrate our existing data to have country codes instead of german country names. For certain reasons we have different models with the country attribute. I needed to make sure that I find all of them and migrate the data properly.

Find relevant classes

First of all I found a way to have all our models in an array. Running following in the rails console:

models = ActiveRecord::Base.connection.tables.map{|model| model.capitalize.singularize.camelize }

In the next step I converted those strings into class names using:

class_names = models.map(&:constantize)

Some entries caused an error like this one ‘NameError: uninitialized constant Audit’ so I just deleted it from the models array :

models.delete(Audit)

Since each ActiveRecord helps us get the column names the next step was just:

class_names.select{|a| a.column_names.include?("country")}.map(&:name)

Which provided me with a nice array of model names which have country as attribute.

Add migration

Here is the resulting migration. Since we only had three different countries I felt safe using hard coded values for them in the migration.

class ChangeCountryNamesToIsoFormat < ActiveRecord::Migration
  @@model_names =  ["Model1", "Model2", "Model3"]
  def up
    @@model_names.each do |model_name|
      model = model_name.constantize
      model.all.each do |object|
        new_country = nil
        case object.country
        when 'Deutschland'
          new_country = 'DE'
        when 'Österreich'
          new_country = 'AT'
        when 'Schweiz'
          new_country = 'CH'
        end
        object.country = new_country
        object.save!
      end
    end
  end

  def down
    @@model_names.each do |model_name|
      model = model_name.constantize
      model.all.each do |object|
        new_country = nil
        case object.country
        when 'DE'
          new_country = 'Deutschland'
        when 'AT'
          new_country = 'Österreich'
        when 'CH'
          new_country = 'Schweiz'
        end
        object.country = new_country
        object.save!
      end
    end
  end
end