Is it a nightmare to manage global settings in your Rails Apps? I used to have this problem, and I was just tired of it, so I contributed to write a gem! check this out:
MC-Settings
As its README says:
This gem provides an easy and Capistrano-friendly way to manage application configuration across multiple environments, such as development, QA, staging, production, etc.
The Problem to solve
Let’s say that you need specific configurations per environment, or even, per server!
Example: I want my stage environment to use a single memcached server, storefront production to use two memcacheds, admin production to have caching disabled and my dev machine to use local memcached.
How would you solve this? The answer is easy: use mc-settings, go to its github page and read the details about it. I’ll describe how we were able to manage different configurations without ugly conditionals.
Settings per environment
I’m assuming a normal rails app folder structure.
config/settings/default.yml:
caching:
enabled: false
memcached:
host: localhost
port: 11211
config/settings/environments/development.yml
caching:
enabled: true
memcached:
host: 127.0.0.1
port: 11211
config/settings/environments/staging.yml
caching:
enabled: true
memcached:
host: 192.168.10.5
port: 11211
config/settings/environments/production.yml
caching:
enabled: false
memcached:
host: localhost
port: 11211
config/settings/stages/admin.yml
caching:
enabled: false
memcached:
host:
port:
config/settings/systems/cluster1.yml
caching:
enabled: true
memcached:
host: 192.168.5.5
port: 11211
config/settings/systems/cluster2.yml
caching:
enabled: true
memcached:
host: 192.168.5.6
port: 11211
Capistrano integration
When writing your capistrano recipes, add this task:
namespace :settings do
desc "Symlinks correct configuration file"
task :symlink_local_file do
system_file_name = "#{current_release}/config/settings/" +
"systems/#{full_stage_name}.yml"
run "cd #{current_release}/config && if [ -f #{system_file_name} ]; " +
"then echo 'symlinking systems/#{full_stage_name}.yml into locals' " +
"&& ln -sf #{system_file_name} #{current_release}/config/settings/local ; fi"
end
end
Then, just call it:
namespace :deploy do
task :default do
...
settings.symlink_local
...
end
end
This will create a symbolic link between your staging config file into config/settings/local folder, mc-settings will load this settings and override any previous value.
In Action
I’ll just show the input in every single environment, and you will get the idea:
Local machine:
rails c test
ree > Setting.cache(:enabled)
=> false
It returned false because test didn’t have specific configuration and mc-settings loaded this value from default.yml
Local machine:
rails c
ree > Setting.cache(:enabled)
=> true
ree > Setting.cache(:host)
=> "127.0.0.1"
ree > Setting.cache(:port)
=> 11211
When running in development mode, since we specified that the cache should be enabled, it returns the local configuration.
Local machine:
rails c production
ree > Setting.cache(:enabled)
=> false
Notice that in production.yml I set cache(:enabled) as false, how cool, isn’t it?
Staging app server
rails c staging
ree > Setting.cache(:enabled)
=> true
ree > Setting.cache(:host)
=> "192.168.10.5"
ree > Setting.cache(:port)
=> 11211
Look at staging.yml, mc-settings return the correct value for this environment, without any manual configuration!
admin app server
rails c production
ree > Setting.cache(:enabled)
=> false
When I saw this I said: yes! now I can disable caching in admin servers very easily without ugly configurations or extra deployment efforts.
cluster1 app server
rails c production
ree > Setting.cache(:enabled)
=> true
ree > Setting.cache(:host)
=> "192.168.5.5"
ree > Setting.cache(:port)
=> 11211
This is where the magic begins, mc-settings + capistrano you can really do fine grain tuning with your configurations and still keep your precious hair!!
cluster2 app server
rails c production
ree > Setting.cache(:enabled)
=> true
ree > Setting.cache(:host)
=> "192.168.5.6"
ree > Setting.cache(:port)
=> 11211
Again, you get a very powerful combination using mc-settings + capistrano, this is how we were able to manage rails configuration across 3 clusters with more than 30 app servers plus the staging servers
Promise to write a new post later on describing how could you get the same mc-settings + capistrano power with services like Heroku and Engine Yard.