Autonomous Machine

Carmen: A Rails plugin for geographic names and abbreviations

On a recent project I became tired of state select and country select, the ubiquitous Rails plugins for providing a list of state or country names in views. I didn't like that their data was defined in code. Or that their data was defined in the view, so validating a model field against them was messy.

I started to refactor country select by moving the list of countries into a Geography module. But then I needed a list of states, and their abbreviations, and it struck me as odd that I needed two plugins that worked differently in order to provide what seemed to be some very basic functionality to my app.

Well she sneaks around the world, from Kiev to Carolina...

Carmen is the result of my frustration: a small unified library that handles country and state names and abbreviations. It stores its data lists in YAML, so it's easy to edit and add new state lists.

Carmen's primary use is providing a list of countries (or states within country), and, optionally, their abbreviations.

Carmen::states('US') => [['Alabama', 'AL'], ['Arkansas', 'AR'], ... ]
Carmen::state_names('US') => ['Alabama', 'Arkansas', ... ]
Carmen::state_codes('US') => ['AL', 'AR', ... ]

Similar methods are available for countries. It also has some convenience methods to assist in converting between names and abbreviations:

Carmen::country_name('US') => 'United States'
Carmen::country_code('Canada') => 'CA'
Carmen::state_code('Manitoba', 'CA') => 'MB'
Carmen::state_name('AZ', 'US') => 'Arizona'

Any of the state methods that require a country code will use a default country code if none is supplied. This defaults to 'US', but can be easily changed for those outside the US:

Carmen.default_country = 'CA'

And of course, it's simple to use Carmen in your model validations:

class Address < ActiveRecord::Base
  validates_inclusion_of :country, :in => Carmen::country_codes
end

Carmen also supplies view helpers that work the same as those in country select or state select, so it should be a drop in replacement in most cases. I've posted the docs, and the code is on Github.