#85 YAML Configuration (revised)
Oct 14, 2012 | 8 minutes | Tools
Keeping passwords and secret tokens in source control is a security risk. Here I show how to move these settings out into a YAML configuration file which can be loaded in as a hash or environment variables.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
If you are using foreman, you can put env vars in .env file. Also, there is a dotenv gem worth checking out
best $9 I've ever spent
Thanks Milovan !
Since Ruby is an interpreted language, what is the drawback to storing configurations/settings in a simple ruby hash in an rb file/Ruby module and then include the file/module? What advantage does parsing a YAML file into a simple ruby data structure yield since Ruby is already pretty darn readable?
I know you could make arguments that you might include your real config file in version control, but that's true for YAML et al. as well.
That's a really simple and interesting idea. Why isn't this more popular? I like it!
planetmcd comment makes me question if using YAML is the right way to use configurations. The only advantage that I see in YAML is that it's portable. But what about in terms of performance what is better YAML or ruby?
I think the only performance issue would be load time. Loading the class is probably quicker than parsing the YAML and then loading the relevant data structures. I've never done a compare, but I'd imagine the difference would not matter much.
I just wondered whether setting up a nested data structure is spartan enough in Ruby that the YAML abstraction is often unnecessary.
I like YAML, and when I use Rails, that's how it works, so I use it. But when I've been doing non-rails stuff lately, I've been experimenting with just using Ruby, e.g.:
and then I can use it like:
As best as I can figure, YAML lets you not worry about quoting strings. But the portability of YAML is not really a big selling point for configs in Ruby. In Java, XML was a idea since it meant you could use a standard, portable format, that didn't get compiled into your code. YAML's readability is a big improvement from XML for configs. But since the Ruby doesn't get compiled, why not use it for configs I wondered?
I find this configuration very useful as well. Further, I prefer to add a defaults section to the YAML config file, and allow let the other sections to inherit from that.
If you use Heroku, it makes sense to use foreman in development. If you do that, you can put all your config vars in a
.env
file.https://github.com/ddollar/foreman/blob/master/lib/foreman/cli.rb#L134
You mention (@7:10) that if you're not using Heroku, you don't use environment variables.
Wouldn't the CONFIG hash solution work on Heroku also? If Heroku itself were looking for a setting in the environment variables, that would be a reason to use environment variables. In all of the screencast examples (auth & mail settings), we have control of both the definition and usage of the configuration method.
That's absolutely true for the examples given in the screencast. However, many of Heroku's plugins depend on ENV configuration; SendGrid for example. So configuring your app to use ENV in those cases allows you to use Heroku's configuration in production and your own locally.
Two relevant gems:
I'll second the
rails_config
comment. I've been using it (in projects for two separate clients), and it does pretty much exactly what I want. It allows for default settings, environment-specific overrides, and local (i.e., not checked-in) overrides. As with the final approach in Ryan's screencast, it makes the config settings available in a global.There are certainly edge cases where it might not work well, but for my uses (passwords, email configuration, API keys, and the like), it's cleaned things up considerably.
Thanks for the tip on rails_config, it's just what I was looking for over here. The built-in support for local overrides is nice, and more elegant than my current home-baked solution.
I have been using Yettings which seems to work well.
Thanks Ryan, good episode. And interesting comments with good links. One thing that I think would complete the railscast well would be the capistrano deploy script. Since you have the file in .gitignore, it will not post to the server with your cap deploy, so you just need to add a command to put the yaml file to the server when you deploy.
Exactly, although I put application.yml in Capistrano's shared directory and symlink it rather than uploading it every time. That way, a developer doesn't need access to the latest production server configuration in order to deploy.
How did you do it?
I have this in my deploy recipe:
When I do cap deploy:setup, it copies the file to:
But when I do cap deploy:cold I see:
And it dies :( - Any ideas?
I fixed the problem by adding this:
woo :)
I like that you can prefix the yaml key with a colon, like so
:symbol:
in your yaml file so you don't have to use symobolize_keys!. Also, if I remember correctly, symbolize_keys! only works one level deep.
I would recommend to use
CONFIG.fetch(:key)
instead ofCONFIG[:key]
. If for some reason the:key
does not exist an KeyError exception will be raised.Another good gem to check out is Settingslogic. While Figaro is easier to set up, Settingslogic allows nested configurations which feels for cleaner code.
Thanks for the tip!
I was using this settings logic: http://speakmy.name/2011/05/29/simple-configuration-for-ruby-apps/
Bad thing is, they aren't always loaded, I had some cases in the workers where the Settings weren't actually available.
What about deploying your app when the application.yml isn't part of your code in git? When working with different developers it's a pain in the ass to keep the application.yml for the production env in sync. Any tips on this one?
I'm also curious about this. If we're not supposed to keep config data in SCM, where does it go?
I usually deploy projects using a configuration management system such as Chef or Puppet. I create templates for the settings files and the templates are populated using data pulled from encrypted data bags on convergence.
I do something similar. You may find the constantinople gem useful.
Put all your non-secret config settings (eg - hostname), as well as "dummy" secrets into a config/app.yml.default file that you store in source control.
Gitignore config/app.yml.
In production, use chef templates to generate config/app.yml. Devs can also maintain their own local over-rides there as well.
If you prefer, instead of keeping config/app.yml.default and overriding with gitignore'd config/app.yml... you can keep config/app.yml in source control, and override with a gitignore'd config/app.yml.override
I'd better use
instead of
Hey guys, I just packaged this all into a gem called
magiconf
. It's super simple and easy to use. Based off of this + figaro. https://github.com/sethvargo/magiconfMy latest revision of reading yaml'ed data in application.rb (1.9 notation):
One less mutation, and it allows specifying environment-dependent settings in both yaml files. It does use mutation though, but as far as I know they (merge! and symbolize_keys!) are both thread-safe.
Wait, if you're gitignoring your application.yml file, how do you get around this in your application.rb?
I'm getting this when I try to run on heroku:
config/application.example.yml
should be a file containing the skeleton of the variables you want to keep secret (don't put real values there); check this in, then in the deployed application rename the skeleton toconfig/application.yml
and manually add the private data.The purpose is to keep private data out of source control. The need here is clear when your SCM is public, but even in a small organization with multiple developer, one might want to set up an environment where not everyone has access to everything.
Thanks for the explanation. I'm wondering though, how would you go about doing this if you're deploying to Heroku where it seems that you can't add or edit anything in the deployed application. I read that it's basically read only because any changes you make to any file are temporary and will be undone whenever you push your source code to Heroku.
@shazebq, this is a little old topic but it's still applicable (and debated!) today. Heroku operates on ENV variables expected in the ENV namespace. It is used by Heroku itself for deployment as well as the 3rd-party plugins that Heroku provides (email, additional DBs, etc...).
Storing env variables in config/application.yml and reading them via code in your application.rb is only useful if your production environment can do the same. As you pointed out, you can't (easily) dynamically add the production-ready application.yml into Heroku's deployment process. Thus, using application.yml is not a good idea for Heroku deployment.
If you use Heroku (as I do for several projects) I recommend using the dotenv gem. In your local development, you have a .env file that stores environment variables. So your app code expects and uses the ENV namespace.
But you have to manually set those ENV vars on Heroku. Currently you can login to your Heroku app and they provide a clean interface to alter your ENV variables. Put your production-ready secrets and keys into that interface and your app will use them when it's deployed.
This way each developer can have their own local .env file with particular configs, yet the production system will always be consistent. The only "gotcha" is when you need to add a new env variable that you have to remember to add it everywhere.
What I have started doing is keeping application environment configs in another repo named "REPO_NAME-environments" where I have folders for development/test/staging/production and applicable config files there. This keeps them versioned and is a single place for them to exist. Goes without saying, but make sure this is a private repo.
Hope you or anyone else reading through these great comments finds this helpful! I recently did a major overhaul of some app configs myself and wanted to throw in my 2 cents.
Check out how I load YAML file config for a basic http authentication in my tutorial
http://aflexsystem.com/how-to-create-a-simple-admin-control-panel-with-ruby-on-rails-in-less-than-9-minutes/
You can use
to check if the file exists first.. and set your heroku variables manually
This was really helpful, just one typo in the ASCIIcast that was a gotcha for me when I copy and pasted.
CONFIG.merge! config.fetch(Rails.env, {})
should be
CONFIG.merge! CONFIG.fetch(Rails.env, {})
Thanks for letting us know, I've corrected the ASCIIcast text :)
Is it certain that "CONFIG.merge! CONFIG.fetch(Rails.env, {})" will pull in heroku environment variables pulled in via heroku config:push from the .env file?
Foreman + dotenv + dotenv-rails + heroku-config
My preferred configuration management tools.
Using them always with your
.env
file either on development or production, in heorku or VPS, with rake or capistrano, on Rails or any app.Rails 3 / 4 with dotenv-rails
Rails + Heroku with heroku-config
Rails + Capistrano with dotenv-capistrano
require "dotenv/capistrano"
Plain old Ruby apps with dotenv
Rake tasks
Note: do not commit your
.env
file but commit the exampleI am using:
It is one line not two and it does not use slashes for OS compatibility.
That's a really simple and interesting idea
Permainan TOGEL ONLINE , Live 24D,Live 48D Dan Dragon Tiger
Permainan Togel Ini Juga Tersedia Hadiah Utama, Hadiah Kedua, Dan Ada Juga Hadiah Ketiga Untuk 3D Dan 4D.
2D : Prize 1 X 70
3D : Prize 1 X 400, Prize 2 X 200, Prize 3 X 100
4D : Prize 1 X 3000, Prize 2 X 2000, Prize 3 X 1000
Ada Juga Pasaran nya :
- Wuhan
- Saga
- Sisilia
- Singapore
- Koln
Ayuk Daftar Diri Anda Dan Bergabung Lah Bersama kami
Bonus Refferal 1% Seumur Hidup ( + Bonus hingga 100% )