Configuring Rails Applications

This week I was configuring an application to run different instances depending on the subdomain requested. This is really quite easy: here’s the basic theory DHH used in Basecamp: http://gist.github.com/45076.

Easy enough. But, now, I want to use this only in some environments. In development I want http://localhost:3000 to just be the development instance (@current_account = Account.first).

I’d love to solve this by adding something like the following to config/environments/development.rb

config.get_instance_from_subdomain = false

Googling, I found a lot of advice about creating custom configuration systems and several plugins that would do it for me. But, IMHO, all of these involved writing too much software. We’ve already got Rails::Configuration, why reinvent the wheel? In my case, at least, there was no need.

Extending the Wheel

Since it’s quite easy in Ruby to extend classes, I added this block to config/environment.rb:

Rails::Initializer.run do |config|
 
  # extend Rails::Configuration
  config.class.class_eval do
   
    def get_instance_from_subdomain
      @get_instance_from_subdomain ||= true
    end
    def get_instance_from_subdomain=(value)
      @get_instance_from_subdomain = value
    end
  
  end
  
  # ...

end

Voila!

Rails::OrderedOptions

But it wouldn’t be a lot of fun to have to define accessors for every property you need to configure if you have several of them. It would be nicer to add configuration options on the fly – as easily as adding values to a hash. Turns out, the Rails team didn’t want to waste keystrokes writing accessors either. Groups of configuration options (like config.action_mailer) are actually instances of Rails::OrderedOptions – an object that lets you add properties at run-time. You can create your own groups of flexible configuration options like this:

Rails::Initializer.run do |config|
 
  # extend Rails::Configuration
  config.class.class_eval do
   
    def application_mailer
      @application_mailer ||= Rails::OrderedOptions.new
    end
  
  end
  
  # ...

end

Now you can define namespaced configuration just by assigning values to properties of config.application_mailer:

config.application_mailer.property1 = false
config.application_mailer.property2 = :awesome