I know that I can set my ENV variables in bash via
export admin_password = "secret"
But is there a way to do it in my rails source code somewhere? My first attempt was something like this in environment/development.rb
ENV['admin_password'] = "secret"
But it didn't work. Is there a way to do this?
How to Set Environment Variables. You can set an environment variable for a one time use. Use this in a terminal, outside of irb, then Ruby will have access to this API_KEY value. This is helpful for API keys, but also to set Rails mode.
Keeping Environment Variables PrivateRemote git repositories such as GitHub are a place to store and share code. If your project is open source, any developer will have access to your code. You don't want to share email account credentials or private API keys with the public.
Use command ENV in rails console. That will return a hash of your environmental values you can access. Alternatively, you can access your environmental variables from your apps root path using the same command and the variables will be returned formatted.
Never hardcode sensitive information (account credentials, passwords, etc.). Instead, create a file to store that information as environment variables (key/value pairs), and exclude that file from your source code management system. For example, in terms of Git (source code management system), exclude that file by adding it to .gitignore:
-bash> echo '/config/app_environment_variables.rb' >> .gitignore
/config/app_environment_variables.rb
ENV['HTTP_USER'] = 'devuser' ENV['HTTP_PASS'] = 'devpass'
As well, add the following lines to /config/environment.rb
, between the require
line, and the Application.initialize
line:
# Load the app's custom environment variables here, so that they are loaded before environments/*.rb app_environment_variables = File.join(Rails.root, 'config', 'app_environment_variables.rb') load(app_environment_variables) if File.exists?(app_environment_variables)
That's it!
As the comment above says, by doing this you will be loading your environment variables before environments/*.rb
, which means that you will be able to refer to your variables inside those files (e.g. environments/production.rb
). This is a great advantage over putting your environment variables file inside /config/initializers/
.
Inside app_environment_variables.rb
there's no need to distinguish environments as far as development or production because you will never commit this file into your source code management system, hence it is for the development context by default. But if you need to set something special for the test environment (or for occasions when you test production mode locally), just add a conditional block below all the other variables:
if Rails.env.test? ENV['HTTP_USER'] = 'testuser' ENV['HTTP_PASS'] = 'testpass' end if Rails.env.production? ENV['HTTP_USER'] = 'produser' ENV['HTTP_PASS'] = 'prodpass' end
Whenever you update app_environment_variables.rb
, restart the app server. Assuming you are using the likes of Apache/Passenger or rails server
:
-bash> touch tmp/restart.txt
In your code, refer to the environment variables as follows:
def authenticate authenticate_or_request_with_http_basic do |username, password| username == ENV['HTTP_USER'] && password == ENV['HTTP_PASS'] end end
Note that inside app_environment_variables.rb
you must specify booleans and numbers as strings (e.g. ENV['SEND_MAIL'] = 'false'
not just false
, and ENV['TIMEOUT'] = '30'
not just 30
), otherwise you will get the errors can't convert false into String
and can't convert Fixnum into String
, respectively.
Storing and sharing sensitive information
The final knot to tie is: how to share this sensitive information with your clients and/or partners? For the purpose of business continuity (i.e. when you get hit by a falling star, how will your clients and/or partners resume full operations of the site?), your clients and/or partners need to know all the credentials required by your app. Emailing/Skyping these things around is insecure and leads to disarray. Storing it in shared Google Docs is not bad (if everyone uses https), but an app dedicated to storing and sharing small titbits like passwords would be ideal.
How to set environment variables on Heroku
If you have a single environment on Heroku:
-bash> heroku config:add HTTP_USER='herouser' -bash> heroku config:add HTTP_USER='heropass'
If you have multiple environments on Heroku:
-bash> heroku config:add HTTP_USER='staguser' --remote staging -bash> heroku config:add HTTP_PASS='stagpass' --remote staging -bash> heroku config:add HTTP_USER='produser' --remote production -bash> heroku config:add HTTP_PASS='prodpass' --remote production
Foreman and .env
Many developers use Foreman (installed with the Heroku Toolbelt) to run their apps locally (as opposed to using the likes of Apache/Passenger or rails server
). Foreman and Heroku use Procfile
for declaring what commands are run by your application, so the transition from local dev to Heroku is seamless in that regard. I use Foreman and Heroku in every Rails project, so this convenience is great. But here's the thing.. Foreman loads environment variables stored in /.env
via dotenv but unfortunately dotenv essentially only parses the file for key=value
pairs; those pairs don't become variables right there and then, so you can't refer to already set variables (to keep things DRY), nor can you do "Ruby" in there (as noted above with the conditionals), which you can do in /config/app_environment_variables.rb
. For instance, in terms of keeping things DRY I sometimes do stuff like this:
ENV['SUPPORT_EMAIL']='Company Support <[email protected]>' ENV['MAILER_DEFAULT_FROM'] = ENV['SUPPORT_EMAIL'] ENV['MAILER_DEFAULT_TO'] = ENV['SUPPORT_EMAIL']
Hence, I use Foreman to run my apps locally, but I don't use its .env
file for loading environment variables; rather I use Foreman in conjunction with the /config/app_environment_variables.rb
approach described above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With