Applications today rely on an ever-increasing number of external services, each requiring their own set of API keys and configuration parameters. It makes a lot of sense to store these settings in environment variables, so your configuration logic can be written once but still allow for tweaks among multiple environments
If you've ever used Heroku, you're not doubt already familiar with this concept, whether you know it or not. The
heroku config commands are effectively just manipulating environment variables on your dynos. Most of Heroku's add-on services also inject environment variables for their own configuration.
Using environment variables is also a great idea for local development. By doing so, you can avoid adding sensitive API credentials into the code repository. Environment variables also allow all the developers on a project to have their own local settings without affecting the rest of the team.
Airbrake.configure do |config| config.api_key = ENV['AIRBRAKE_API_KEY'] end
If you're using Pow for local development, you may be familiar with the
.powenv file, which can be used to expose environment variables to your local app. Unfortunately, this only gets us halfway to where we need to be. It sets up the environment for the app server, but what about the command line tools? It would be nice if we could use those same environment variables when running tests, Rake tasks, and the Rails console.
Making Environment Variables Accessible to Binstubs
Note: If you haven't read my post on Implicit Gemsets with
rbenv yet, go read that first, as the material below builds on the concepts outlined there.
Well, as it turns out, Bundler has the ability to modify the shebang line used by the binstubs it outputs. We're going to use that to create a custom wrapper around the
ruby executable that loads our environment variables before handing off execution to the Ruby interpreter.
Here's what the wrapper looks like:
#!/bin/bash for file in .powrc .powenv; do if [ -f $file ]; then source $file fi done /usr/bin/env ruby $@
This script is responsible for loading the
.powenv files from our local application into the environment using the
source command, which makes all the environment variables defined in those files available to the currently running shell. It then passes all the given arguments (
$@) to the
I've placed the script into the file
~/.bundle/powenv. You'll also want to make sure it's executable:
chmod +x ~/.bundle/powenv
Once you've done that, run the following command from a directory inside your app:
bundle config --local shebang "$HOME/.bundle/powenv # ruby"
There a few things you should note here.
--local" flag dictates that this setting will only be applied to the Bundler configuration for this particular app. If you want to use it in all your apps, you can use
$HOME" variable will be replaced with the path to your home directory before the shebang line is written to the configuration file. This is important because the shebang line is not evaluated at runtime, so it won't be able to interpolate variables like
$HOMEor even the
~home directory expansion.
# ruby" bit at the end is a trick to let Ruby know that our binstubs are, indeed, Ruby scripts. Without it, Ruby will complain with an error like this:
ruby: no Ruby script found in input (LoadError)
Basically, it just needs to see the string "
ruby" somewhere in the shebang line, so we add it as a comment at the end.
bundle to regenerate the binstubs with the new shebang, and you should be all set.
From now on, all the commands you execute via binstubs will have access to the same environment variables as your app running under Pow.