Extending Rails::Configuration
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