In my current project based on Ruby on Rails framework, I need to store application specific configuration somehow. There are several approaches I’ve found in Internet: AppConfig plugin, several methods described on the HowtoAddYourOwnConfigInfo wiki page, but neither one looks “config-like”. Me with my friend, Alexey Kovyrin, discovered all of them and decided to use YAML-file as a configuration format. In my opinion, the ideal configuration file looks like this:
1 2 3 4 5 6 7 8 9 10 11 | common: support_email: [email protected] root_url: myhost.com photos_max_number: 6 production: email_exceptions: true development: root_url: localhost:3000 photos_max_number: 10 |
In this example you can see three sections: common will be used as a base configuration for all environments, production and development — environment specific options. Optional sections are production, development, and testing, or any other custom environment name. I’ve placed this file in config/config.yml and created lib/app_config.rb which looks like this:
1 2 3 4 5 6 7 8 | # Load application configuration require 'ostruct' require 'yaml' config = YAML.load_file("#{Rails.root}/config/config.yml") || {} app_config = config['common'] || {} app_config.update(config[Rails.env] || {}) AppConfig = OpenStruct.new(app_config) |
Now I’m able to use constructions like AppConfig.support_email
and AppConfig.root_url
. Looks like I’ve kept all my configs as DRY as possible :-)
сделать это в yaml и не гадить environment
DRY out your database.yml
Yaml Cookbook там где “merge key”
салют
Во-первых, лично мне не нравится, как выглядит
2
3
4
5
6
7
8
9
10
11
12
13
support_email: [email protected]
root_url: myhost.com
photos_max_number: 6
production:
<<: *common
email_exceptions: true
development:
<<: *common
root_url: localhost:3000
photos_max_number: 10
Во-вторых, код все равно останется в виде
2
::AppConfig = OpenStruct.new(config.send(RAILS_ENV))
Имхо, уродство конфига не оправдание программисту, который сэкономил две строчки кода.
К тому же у себя я их вынес в плагин, чтоб не мешалось под ногами и можно было юзать в разных проектах.
Кстати, спасибо за ссылки. Очень полезно :-)
Похожим образом сделана конфигурация в php symfony framework (который появился под воздействем рельсов)
http://www.symfony-project.com/book/trunk/configuration
Небольшая модификация кода на случай, если секция common не содержит данных или отсутсвует как таковая:
2
3
4
5
env_config = config.send(RAILS_ENV)
common = config.common || {}
common.update(env_config) unless env_config.nil?
::AppConfig = OpenStruct.new(common)
Спасибо! В некоторых проектах может быть полезно :-)
Да не за что, мне уже помогло :)
[…] solutions have been posted for handling application level config file but this solution is by far the best. It’s simple, DRY and works. Try it. You will love […]
Many thanks for the great idea. I’ve decided to go further and now config file is parsed with ERB, one can have another file to override the values in the main file (when you place config.yml to svn and need specific values in your working copy) and config values can not be overwritten in the application (by mistake). Please check it out.
Hi Dmitry,
I have expanded your idea into a plugin: http://agilewebdevelopment.com/plugins/application_configuration
I have been using your setup with great pleasure in couple of last projects.
Many thanks!
Karel
[…] plugin which does exactly that, using YAML. It’s based on the technique described by Dmytro Shtefluk and uses OpenStruct to parse the config file and supports RAILS_ENV specific settings.Borrowing […]
This code does’t work in ‘test’ environment (Rails 2.0.2).
Problem with:
It’s strange that config.test() work, but confg.send('test') not.
I don’t know why. Can anyone explain this behaivor?
It works for my Rails 2.0.2 project:
2
3
4
5
require 'ostruct'
require 'yaml'
config = OpenStruct.new(YAML.load_file("#{RAILS_ROOT}/config/chef.yml"))
::AppConfig = OpenStruct.new(config.send(RAILS_ENV))
Test:
2
3
assert_not_nil AppConfig.test_base
end
Passes. When I change it to assert_nil it fails, and I see that it was actually set.
If you are getting errors when using this in your test environment you forgot to add “test:” to your .yml file
The example in this article had production and dev, but for some reason omits test
[…] http://kpumuk.info/ruby-on-rails/flexible-application-configuration-in-ruby-on-rails/ http://blog.bleything.net/2006/06/27/dry-out-your-database-yml […]
[…] HT: Dmitro Shteflyuk […]