My company is currently working on multiple Rails sites simultaneously. This involves multiple development groups and an infrastructure team tasked with providing multiple environments (continuous integration, qa, staging and production) for each project. There are many elements required to make this happen and we are in the process of working through the kinks. This post is about one of the solutions, convention of configuration.
There are definitely some things that have been done with the current version of Rails to help us. There are definitely some things I would like to see changed in a near-future release (3.0?) of Rails that would provide a more ideal configuration solution. I’ll get to that in a bit, but let’s start off with what can be done now.
Take advantage of the environment files in RAILS_ROOT/config/environments. These should be THE place you look for your applications’ configuration. Take advantage of the fact you can provide a default setting in RAILS_ROOT/config/environment.rb and then override that setting in RAILS_ROOT/config/environments/production.rb or any environment you choose. Also take advantage of the fact you can create an environment called staging and as long as there is a corresponding RAILS_ROOT/config/environments/staging.rb, you’re good.
How do you take advantage of this? This simplest solution I’ve found is to create a file in your RAILS_ROOT/config directory that defines the configurations you need. Here is a sample file we’ll call mycompany.rb:
module MyCompany
module Configuration
def google
MyCompany::Google
end
end
module Google
class << self
attr_accessor :api_key
end
end
end
Rails::Configuration.send :include, MyCompany::Configuration
Then in your RAILS_ROOT/config/environment.rb add the following line after the require for ‘boot’:
require File.join(File.dirname(__FILE__), 'mycompany.rb')
This will require your file and allow you to do something very simple and expected in your Rails::Initializer block:
config.google.api_key = 'THISISSSOMEVALIDAPIKEY'
If you create a default in environment.rb and override for other environments it will work as expected. You can later reference this through your app as MyCompany::Google.api_key.
As you need more configurations, you can expand your mycomany.rb functionality and you will have your one expected place to go for both the development and infrastructure teams.
This is good, but it’s not perfect. We can’t attempt to reach perfection with the current configuration construct provided by Rails.
What’s wrong? Well, instead of having the RAILS_ROOT/config/environments directory contain environment files, I would like them to contain environment directories. For example, RAILS_ROOT/config/environments/production/environment.rb would be ideal. This would allow applications like Capistrano to take advantage of this construct and place its environment related files in these directories. A single place to look for production related settings would rock!
In order to avoid conflicts between development environments, development and test should not be stored in your source control. Instead, give everyone a helping hand and start them out with an example (that should be in source control):
RAILS_ROOT/config/environments/development/environment.rb.example
This example should be updated as needed to provide the latest configuration examples.
Another feature wish for the RAILS team is to do away with database.yml. I think these settings belong with the rest. Think of the code duplication you could save! I could set my adapter, encoding and database in RAILS_ROOT/config/environment.rb and leave the username password and host to be overridden by my different environments.
You could start out with this:
config.database.adapter = 'mysql'
config.database.encoding = 'utf8'
config.database.database = 'my_database'
Then in RAILS_ROOT/config/environments/production/environment.rb you could just
config.database.username = 'super_secret_user'
config.database.password = 'super_secret_pass'
config.database.host = 'another_host'
I would like to hear what you think and if there are other conventions your team has adopted. The more we can reduce the amount of documentation required between teams and develop an expectation, the more efficient our company will be.
We are working every day to reach this goal and I will continue to share our findings in hope that they can be further refined.

Heya Andy- I recently had a need to do something similar in one of my apps and I created a simple initializer that used an OpenStruct and a YAML::load passing the RAILS_ENV to get a particular section — similar to how Rails does database.yml I believe. The idea isn’t 100% mine — read it somewhere (not sure where). I’m not sure if this is better or worse or just different. I agree it would be nice to have somewhere uniform to stash ‘extra’ config info though.
Know any reasons to avoid OpenStruct or YAML in general? YAML just seems easier for the ‘less experienced’ to read and understand.
Hey Phil!
I don’t have anything against config files like YAML. It’s only an issue when they contain environment sections like database.yml. For each additional file that has its own environment sections you are creating another potential failure point when it comes to environment configuration.
None of this is probably an issue with small teams. When you involve multiple dev teams and a separate infrastructure team, this convention is very, very helpful.
Thanks for typing this up. Glad to see you advocating this publicly after the conversation we had. Hope some people are convinced.
Thanks Lark! I really enjoyed the discussion and thought it was worthy of the public forum. Hopefully it’s something others agree on or have already done privately and support this type configuration change within Rails.