#85
Dec 23, 2007

YAML Configuration File

Application configuration shouldn't be spread throughout your code base. Instead a much better place to put it is an external YAML file. See how to do that in this episode.
Tags: tools
Download (13.7 MB, 7:03)
alternative download for iPod & Apple TV (9.2 MB, 7:03)

Resources

# config/initializers/load_config.rb
APP_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")[RAILS_ENV]

# application.rb
def authenticate
  if APP_CONFIG['perform_authentication']
    authenticate_or_request_with_http_basic do |username, password|
      username == APP_CONFIG['username'] && password == APP_CONFIG['password']
    end
  end
end
# config/config.yml
development:
  perform_authentication: false

test:
  perform_authentication: false

production:
  perform_authentication: true
  username: admin
  password: secret

RSS Feed for Episode Comments 36 comments

1. Jim Dec 24, 2007 at 01:59

Thanks for this one, and happy holidays!


2. ash Dec 24, 2007 at 02:38

Thank you for sharing! Merry Christmas!


3. Mike Dec 24, 2007 at 04:20

Merry Christmas!

Good luck with the railscasts next year!


4. thom Dec 24, 2007 at 05:13

I'm using the following in `config/initializers/app_config.rb`:

  require 'ostruct'
  require 'yaml'
  
  # Load application configuration
  config = OpenStruct.new(YAML.load_file("#{RAILS_ROOT}/config/application.yml"))
  ::AppConfig = OpenStruct.new(config.send(RAILS_ENV))

Now I can use it in my application like this

  AppConfig.perform_authentication


5. nelson jr Dec 24, 2007 at 05:13

Merry Christmas, guys! :-)

More success for all on next year!

Ryan Bates, thks for the casts on 2007, and share more on 2008. :-)

[again, srry my english]

[]s


6. firefly Dec 24, 2007 at 07:00

i do something very similar to this with my .yml files. if you don't want to commit your username/password in your repository like me, you can use a capistrano task like

task :create_config_config do
  set :a_username, Capistrano::CLI.password_prompt('admin_username: ')
  set :a_password, Capistrano::CLI.password_prompt('admin_password: ')
  contents = render_erb_template(File.dirname(__FILE__) + "/templates/config.yml.erb")
  put contents, "#{shared_path}/config/config.yml"
end


7. Jose Dec 24, 2007 at 07:08

Merry Christmass!


8. Henrik N Dec 24, 2007 at 12:42

I've been doing this for a while, too. This is what I do to get ERB in my YAML (like in fixtures). It also uses ostruct as described by thom above.

  require 'ostruct'
  raw_config = File.read("#{RAILS_ROOT}/config/config.yml")
  erb_config = ERB.new(raw_config).result
  config = YAML.load(erb_config)[RAILS_ENV]
  Site = OpenStruct.new(config)

I can now do stuff like

foo_path: <%= RAILS_ROOT %>/tmp/foo


9. Bala Dec 24, 2007 at 14:50

Why do we need to use this method when Rails 2.0 has initializers? I can declare all my configuration under initializers directory, right?

I could have s3_config, mailer settings etc in its own initializer.


10. Michael Dec 25, 2007 at 07:30

if i add the first line:
APP_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/config.yml")[RAILS_ENV]

then:

=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
Exiting
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:133:in `load': syntax error on line 7, col 11: `' (ArgumentError)
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:133:in `load'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:144:in `load_file'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:143:in `open'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/yaml.rb:143:in `load_file'
from /Users/michaelvoigt/Documents/private/projects/kraeftemessen/trunk/kraeftemessen/rails/kraeftemessen/config/environment.rb:84
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `require'
from /Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:496:in `require'
... 23 levels...
from /Library/Ruby/Gems/1.8/gems/rails-2.0.2/lib/commands/server.rb:39
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:27:in `require'
from script/server:3


11. Michael Dec 25, 2007 at 07:41

I have foregot the require 'yaml', SORRY!


12. noocx Dec 26, 2007 at 01:01

Thanks for the new cast and Merry Christmas!


13. Anonymous Dec 27, 2007 at 18:38

What happened to Convention over Configuration? So if you have a bunch of lil configuration options, whats the point from deviating away from what Rails gives us for configuration options? I'm lost...


14. Jaime Iniesta Dec 28, 2007 at 07:24

Thanks for this and the other 84 railscasts! You make me feel not so lonely on my freelance life :)


15. Paul Smith Dec 28, 2007 at 14:07

I love these RailsCasts. Every single on is amazing. Thanks


16. aleco Dec 28, 2007 at 14:26

I've always wanted to find a way to not have any passwords in my SVN. But, even with your suggestion, how would I do that when e.g. using deprec (the cap deply taks available at deprec.org)?

The only solution I can see is completely ignoring the config.yml in the SVN and keeping it far away from the app directory (as something like /var/www/apps/appname/current is replaced on each deploy). So, should one put it in /etc/ instead, or is there a nicer solution?


17. Ryan R. Dec 29, 2007 at 13:36

With HTTP Basic authentication, can you also use OpenID? A screencast on that would be tremendously helpful. Thanks for the great work!


18. August Lilleaas Jan 04, 2008 at 17:55

I love these kinds of railscasts - being recipes instead of re-iterations of stuff you can find in the API etc. Keep 'em coming!


19. Herb Jan 17, 2008 at 11:31

Well done. A very useful screencast and hard to find much info re: this online.


20. Dan Pickett Jan 30, 2008 at 09:27

What about putting configuration in the database? I know wordpress does something like this and I'd be interested in what the Rails community thinks about it.


21. Vivek Khokhar Jan 31, 2008 at 03:22

Since we are loading configs on server startups,
Is there anyway to change & reload config file/table without server restarts ?


22. Erik Petersen Apr 21, 2008 at 14:50

This is a pretty common app configuration pattern but for me it needs some rubification. I do pretty much the same thing but don't use a constant Hash, rather a class to manage the settings:

In lib/configuration.rb:

class Configuration
 @@settings = YAML::load_file('config/myconfig.yml')[RAILS_ENV]
 class MissingConfigOptionError < StandardError; end
 def self.method_missing(key)
  raise MissingConfigOptionError("#{key.to_s} is not in the config file") unless @@settings.include?(key.to_s)
  @@settings[key.to_s]
 end
end

That's it, there is nothing else to do. Create a config/myconfig.yml file with all the same stuff as in this railscast:

In config/myconfig.yml:

development:
  foo: "bar"

production:
  foo: "yummy"

To fetch and use the settings anywhere in your code, model, controller or view do:

x = Configuration.foo # => "bar"

Customize to suit. Maybe store the settings with mem_cache in a production environment and have a rake task to reload it or handle missing config options differently with perhaps a reasonable default (not a good idea IMHO) or add a test for the existence of a given key.

You could also make this a plugin without a problem by putting it in vendor/plugins/my_config_hotness/init.rb instead of lib/configuration.rb. Six and one half dozen.

Enjoy.

PS. This is not my idea. Someone a lot smarter than I put me on to it but went even further to allow for nested groups:

development:
  foo: "bar"
  bar:
    foo: "yummy"

x = Configuration.bar.foo # => "yummy"

But I can't for the life of me find the page where I saw it done and I guess I failed to bookmark it :(


23. Erik Petersen Apr 21, 2008 at 14:58

Oh, I forgot to mention that the config file doesn't get loaded until the first time you try to access a setting (lazy loading). If you don't fetch a config setting value with Configuration.xxx it adds zero overhead. Ruby gives you this for free.


24. Chase Southard May 12, 2008 at 14:04

Can this be used with Helpers?

If so, what am I missing?

I'm getting a template error when using a method defined in application_helper.rb to return the key in that appears to be nil.

You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]

Thanks.


25. Chase Southard May 12, 2008 at 19:14

Yes it does work with helpers provided that you actually load the correct part of the yaml file.

Thank again, Ryan!


26. linki Aug 19, 2008 at 15:12

:-) merry christmas, ryan


27. Henrik N Oct 21, 2008 at 04:38

I've started naming my initializer "_site.rb". The initializers are loaded alphabetically, and you want this one to be first, if you ever use the configuration values in other initializers (e.g. initializers/mail.rb for mailer settings).


28. Joe Adams Dec 04, 2008 at 20:04

I am experiencing the same difficulty as No. 11: Michael Dec 25, 2007.
In 12 Michael Dec 25 he states "I have forgotten the require 'yaml', SORRY!"
 Can you tell me what he is referring to and where to place the 'require yaml'
Thank you all WHAT A GREAT RESOURCE!


29. RaislNewbie Mar 20, 2009 at 18:24

I've followed the RailsCast and have settings that look like this:

development:
   images_path: \\sysimages\2009\

when the initializer runs, it fails with an error that suggest that it doesn't allow for the backward slashes. How do store a string that is a path in a YAML file that Ruby can load? Thanks in advance


30. RailsDevSea Mar 20, 2009 at 19:21

I need to store settings by environment but started off simply with my config file at: \config\config.yml. The only setting I had was this:
attachment_volume: \\attach\transfers

With this, cod I'm able to load the file within my initializer and reference it just fine from calling code within an ActiveRecord model class. So far so good.

Since this setting is a server location that varies by environment, I tried to use the by-environment structure and changed my config file to this:
development:
     attachment_volume: \\attach\transfers

test:
     attachment_volume: \\attach\test\transfers

I get the following error during that indicates it didn't like the second instance of the colon on the second line. Here is the real error: Uncaught exception: syntax error on line 1, col 20: ` attachment_volume: \\atlas\transfer\greenlight\predevelopment\attachments'

Here is full error stack:

Exiting C:/Ruby/lib/ruby/1.8/yaml.rb:133:in `load'
 C:/Ruby/lib/ruby/1.8/yaml.rb:133:in `load'
 C:/Ruby/lib/ruby/1.8/yaml.rb:144:in `load_file'
 C:/Ruby/lib/ruby/1.8/yaml.rb:143:in `open'
 C:/Ruby/lib/ruby/1.8/yaml.rb:143:in `load_file'
 C:/TFS/GreenLight/DEV/server/config/initializers/load_config.rb:2
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load_without_new_constant_marking'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:521:in `new_constants_in'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load'
 ./script/../config/../vendor/rails/railties/lib/initializer.rb:550:in `load_application_initializers'
 ./script/../config/../vendor/rails/railties/lib/initializer.rb:549:in `each'
 ./script/../config/../vendor/rails/railties/lib/initializer.rb:549:i
n `load_application_initializers'
 ./script/../config/../vendor/rails/railties/lib/initializer.rb:167:in `process'
 ./script/../config/../vendor/rails/railties/lib/initializer.rb:112:in `send'
 ./script/../config/../vendor/rails/railties/lib/initializer.rb:112:in `run'
 C:/TFS/GreenLight/DEV/server/config/environment.rb:16
 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:153:in `require'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:521:in `new_constants_in'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:153:in `require'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/rails.rb:147:in `rails'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:113:in `cloaker_'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/lib/mongrel/configurator.rb:149:in `call'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/lib/mongrel/configurator.rb:149:in `listener'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:99:in `cloaker_'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/lib/mongrel/configurator.rb:50:in `call'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/lib/mongrel/configurator.rb:50:in `initialize'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:84:in `new'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:84:in `run'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/lib/mongrel/command.rb:212:in `run'
 C:/Ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:281
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load_without_new_constant_marking'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:521:in `new_constants_in'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load'
 C:/TFS/GreenLight/DEV/server/vendor/rails/railties/lib/commands/servers/mongrel.rb:64
 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:153:in `require'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:521:in `new_constants_in'
 C:/TFS/GreenLight/DEV/server/vendor/rails/activesupport/lib/active_support/dependencies.rb:153:in `require'
 C:/TFS/GreenLight/DEV/server/vendor/rails/railties/lib/commands/server.rb:49
 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
 C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
 ./script/server:3
 C:/Ruby/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.4/lib/ruby-debug.rb:101:in `debug_load'
 C:/Ruby/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.4/lib/ruby-debug.rb:101:in `debug_program'
 C:/Ruby/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.4/bin/rdebug-ide:82
 C:\Ruby\bin\rdebug-ide:19:in `load'
 C:\Ruby\bin\rdebug-ide:19
 -e:2:in `load'
 -e:2
Uncaught exception: syntax error on line 1, col 20: ` attachment_volume: \\atlas\transfer\greenlight\predevelopment\attachments'

Has anyone been able to get the by environment structure load to work? Please advise? Thanks in advance.


31. lale May 05, 2009 at 22:14

Thanks for sharing how to do.Although too much technical,you explained in a simple way so most of people could follow easily.


32. Stewart Johnson Aug 01, 2009 at 01:49

Thanks for the great screencast!

I recently started using configatron for this kind of configuration:

http://github.com/markbates/configatron/tree/master

Highly recommended!


33. Estetik Sep 25, 2009 at 08:19

Thanks for informations..


34. Kelsr Nov 09, 2009 at 07:04

<a href="http://www.uswowgold.com">wow gold</a>
<a href="http://www.ecmmo.com">cheap wow gold</a>


35. wholesale nike shoes Jan 13, 2010 at 23:19

A very good article, I will always come in.


36. fashion scarves Jan 13, 2010 at 23:19

Such a good article, caught my sympathy!
-

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source