Ruby Tricks 1 - Environment Variables in Config Files

In a recent conversation, we were discussing the practice that we should not store values such as API Keys in the configuration file, but instead load them from an environment variable. The reference was to how the database.yml in Rails allows us to provide the details as environment variables in production. I needed to store some such values for some API tests that I was building using RSpec, and decided to find out how Rails does it – and realised that it’s blindingly obvious.

I’m just putting this here so that I remember it for the next time I need it – if it helps you, great… that’s a bonus!

If you’re using a normal YAML configuration file, you will be familiar with a code snippet that looks like this:

1
2
3
require 'yaml'
config = YAML.load_file(File.dirname(File.expand_path(__FILE__)) + '/../config/config.yml')
puts config["api_key"]

Basically, assuming you run this from the /lib folder, you want to find the config.yml file that is in the relative folder ../config form here, and load it using YAML. This returns a hash and you can then use the individual keys from there. For this, you would need your config.yml to look something like this:

1
2
---
api_key: 'some-text-that-is-key'

Let’s say that we now want it to actually read something from the environment. In Ruby, you get access to the Environment Variables hash using ENV – so, a value such as SystemRoot set in the environment would be read as ENV['SystemRoot'] into your program.

What we want to use is a YAML file that looks like this but, of course, regular YAML will not help read in the Environment Variable.

1
2
---
api_key: <%= ENV['APIKeyValue'] %>

What we want to do is get a way to execute the Ruby code to return the value of ENV['APIKeyValue] and you’ll notice that the line looks a lot like ERB (if you’ve come across it). So, that’s the answer – we use ERB (Embedded Ruby).

Basically, we need to do this:

  • Load the contents of the config.yml into a string
  • Use ERB to run the code ENV['APIKeyValue] and produce a result with the value substituted
  • Load that into YAML and parse it to get the configuration hash

This is what it would look like in simple step-by-step code:

1
2
3
4
5
6
7
8
require 'yaml'
require 'erb'

file = File.dirname(File.expand_path(__FILE__)) + '/config.yml')
string = File.read(file)
erb_out = ERB.new(File.read(File.dirname(File.expand_path(__FILE__)) + '/config.yml')).result
config = YAML.load(erb_out)
puts config['api_key']

or, in fewer lines:

1
2
3
4
require 'yaml'
require 'erb'
config = YAML.load(ERB.new(File.read(File.dirname(File.expand_path(__FILE__)) + '/config.yml')).result)
puts config["api_key"]

That’s all there is to it!

comments powered by Disqus