Ruby setting ENV variables on a mac - ruby-on-rails

I would like to try an keep my development machine as close as the production server (heroku in this case).
Heroku lets you define config vars ie.
config:add key=val
This is now pretty secure as secret key values are not stored in my code.
Do you know how and where can I create such environment variables per app on my local mac machine.
I have googled this and as of yet not found a good solution. Any ideas ?
Thanks in advance.

Thanks Zabba, But I have actually found a great way for me.
I am using POW to run my local apps and reading the docs I have found out that you can set Environment Vars by adding a .powenv file in the root of my app ie.
export API_KEY='abcdef123456'
You can then use in your app like normal ie.
api_key = ENV['API_KEY']
Pretty kool stuff.

Here's a way:
Go to http://railswizard.org/ and add only "EnvYAML" to the template. Click finish and then click on the generated .rb file. See how that code is using a file config/env.yml to set ENV vars.
Here is how it is done, thanks to http://railswizard.org/:
In your app's directory:
Append in config/application.rb:
require 'env_yaml'
Create a file called lib/env_yaml.rb:
require 'yaml'
begin
env_yaml = YAML.load_file(File.dirname(__FILE__) + '/../config/env.yml')
if env_hash = env_yaml[ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development']
env_hash.each_pair do |k,v|
ENV[k] = v.to_s
end
end
rescue StandardError => e
end
Create a file called config/env.yml:
defaults: &defaults
ENV_YAML: true
some_key: value
development:
<<: *defaults
test:
<<: *defaults
production:
<<: *defaults
Note that ENV is not a Hash - it only appears so because of the use of []. That is why in lib/env_yaml.rb an each loop is setting in ENV the value of each value found in the config/env.yml - because we cannot assign a Hash directly to ENV.

I'm not using pow but rvm and bash. I was able to set environmental variables by following the instructions at this Peachpit blog post.
Like the other answers, I had to add commands like export TWILIO_ACCOUNT_SID="XXX"but to my ~/.profile file.
Then, accessed the variables in my code with:
account_sid = ENV["TWILIO_ACCOUNT_SID"]

Put your environment variables in a .env file and foreman will pick them up automatically.

Related

How do I get Rails to recognize environment variables defined in config/environment_variables.yml?

With Rails 5, if I create a file, config/environment_variables.yml, that contains
development:
MY_VAR: abcdef
What do I need to do to get the Rails environment to recognized that environment variable? Right now, when I go to my console (by typing "rails console") on my local machine, it isn't turning up anything ...
2.4.0 :001 > ENV['MY_VAR']
=> nil
If you don't wish to use a gem, you can place this in your config/application.rb
# Load application ENV vars and merge with existing ENV vars. Loaded here so you can use the values in initializers.
ENV.update YAML.load_file('config/application.yml')[Rails.env] rescue {}
Then your config/application.yml file should look like:
development:
API_KEY: 12345
staging:
API_KEY: 67890
Be sure to restart your server, then you can access the variables as you desire with ENV['API_KEY'].

Using Figaro and Secrets.yml to Manage Env Variables

I have a rails 4.1 app and I'm trying to organize my env variables. As of right now I have a secrets.yml file in my config/ folder. I also installed the figaro gem. My goal was to have all my env variables in the application.yml (not checked into git) file and then use the secrets.yml (checked into git) file to map the variables from appliation.yml to the application. When I print the files using Rails.application.secrets It just shows hashes that look like this:
:salesforce_username=>"ENV['SALESFORCE_USERNAME']"
None of my external services are working with this env variables setup. When I view the traces, the actually ENV['ACCOUNT_ID'] are being passed through in the requests like this:
v2/accounts/ENV['ACCOUNT_ID']/envelopes
In addition, I cannot access my env variables using Rails.application.secrets.account_id in my app.
secrets.yml
development:
account_id: <%= ENV['ACCOUNT_ID'] %>
aplication.yml
development:
ACCOUNT_ID: "123456"
application.rb
# preload tokens in application.yml to local ENV
config = YAML.load(File.read(File.expand_path('../application.yml', __FILE__)))
config.merge! config.fetch(Rails.env, {})
config.each do |key, value|
ENV[key] = value.to_s unless value.kind_of? Hash
end
The gem provides a generator:
$ rails generate figaro:install
The generator creates a config/application.yml file and modifies the .gitignore file to prevent the file from being checked into a git repository.
You can add environment variables as key/value pairs to config/application.yml:
GMAIL_USERNAME: Your_Username
The environment variables will be available anywhere in your application as ENV variables:
ENV["GMAIL_USERNAME"]
This gives you the convenience of using the same variables in code whether they are set by the Unix shell or the figaro gem’s config/application.yml. Variables in the config/application.yml file will override environment variables set in the Unix shell.
In tests or other situations where ENV variables might not be appropriate, you can access the configuration values as Figaro method calls:
Figaro.env.gmail_username
Use this syntax for setting different credentials in development, test, or production environments:
HELLO: world
development:
HELLO: developers
production:
HELLO: users
In this case, ENV["HELLO"] will produce “developers” in development, “users” in production and “world” otherwise.
You say the ENV variables are being "passed through in the requests", but when I look at your code snippets I think the variables aren't ever being detected as such in the first place.
If you want to inject a variable into a string, double-check that you are using the following format, especially the # and {}:
important_string = "v2/accounts/#{ENV['ACCOUNT_ID']}/envelopes"
On a more general note, if you're unsure what environment variables are being set in a given environment, the easiest way to double-check is to open up the Rails console and query ENV like so:
$ rails console
> puts ENV.keys # find out what ENV vars are set
=> (returns a long list of var names)
> puts ENV['DEVISE_PEPPER']
=> "067d793e8781fa02aebd36e239c7878bdc1403d6bcb7c380beac53189ff6366be"

How to use secrets.yml for API_KEYS in Rails 4.1?

In one of my recent projects I started out by .gitignoring the files containing secrets and environment variables. So the entire project is committed to the repo except the files that contain third party secrets such as that of Stripe, Twitter API or Facebook Graph or internal api_keys, ala the ./config/initializers/secret_token.rb file.
Now I am at a point where the project is about to go live (excited!) and I need to port all the environment variables on to the production server using Capistrano i.e. cap production deploy.
[Edit 4: Yr, 2018]
In case of initializers/secret_token.rb it is clear that Rails 4.1 has a new way of handling secrets.yml file that pulls in the :secret_key_base value to the production server. Here, I recommend using the capistrano-secrets-yml gem which works right out of the box and is dead simple to use.
What is left is the way to carry other secrets like API_KEYS, APP_IDs etc. to the production server without checking any of those into the repo. How to do this, what is the most recommended/securest way or the best practices?
NOTE: I'll be editing the question as it progresses/I get more clarity.
EDIT1: Server is a Ubuntu/Linux VPS on DigitalOcean [Answer to Denise, below].
EDIT2: Can the env_variables/secrets be carried over to the server via secrets.yml? Secret_token for sessions is not the only secret after all! [Answered on Edit3]
EDIT3: Yes! It's possible to send in the API_keys via secrets.yml according to this blog. Will share my findings in sometime. :-)
First rule: DO NOT CHECK-IN secrets.yml into the repo.
All right, here's how a secret.yml would look:
development:
secret_key_base: 6a1ada9d8e377c8fad5e530d6e0a1daa3d17e43ee...
# Paste output of $ rake secret here for your dev machine.
test:
secret_key_base: _your_secret_ as above
production:
secret_key_base: <%= secure_token %>
STRIPE_PUBLISHABLE_KEY: 'Put your stripe keys for production'
STRIPE_SECRET_KEY: 'Put actual keys for production here'
FB_APP_SECRET: 'same as above'
FB_CALLBACK_URL: 'FB url here'
FB_CALLBACK_UPDATE_URL: 'FB url here'
GOOGLE_KEY: 'Put your keys for production'
GOOGLE_SECRET: 'same as above'
TWITTER_KEY: 'same as above'
TWITTER_SECRET: 'same as above'
TWITTER_USERNAME: 'same as above'
LINKEDIN_KEY: 'same as above'
LINKEDIN_SECRET: 'same as above'
Note the secure_token up there in the production: block. On production server I'm using an initializer to dynamically generate secret_tokens on-the-fly.
sidenote: be careful about spaces and tabs inside the .yml file. It must be properly formatted and spaced (such as having a space after the ':' symbol).
To set it up on production you could then scp the file directly from your local or use the capistrano-secrets-yml gem.
This will not work. See an updated method as per #OddityOverseer's answer below.
To access the environment variables in your app environments/production.rb use:
FB_APP_SECRET = ENV['FB_APP_SECRET']
FB_CALLBACK_URL = ENV['FB_CALLBACK_URL']
FB_CALLBACK_UPDATE_URL = ENV['FB_CALLBACK_UPDATE_URL']
GOOGLE_KEY = ENV['GOOGLE_KEY']
GOOGLE_SECRET = ENV['GOOGLE_SECRET']
TWITTER_KEY = ENV['TWITTER_KEY']
TWITTER_SECRET = ENV['TWITTER_SECRET']
TWITTER_USERNAME = ENV['TWITTER_USERNAME']
LINKEDIN_KEY = ENV['LINKEDIN_KEY']
LINKEDIN_SECRET = ENV['LINKEDIN_SECRET']
UPDATED August-2016:
To access the environment variables in your app environments/production.rb use:
FB_APP_SECRET = Rails.application.secrets.FB_APP_SECRET
FB_CALLBACK_URL = Rails.application.secrets.FB_CALLBACK_URL
FB_CALLBACK_UPDATE_URL = Rails.application.secrets.FB_CALLBACK_UPDATE_URL
GOOGLE_KEY = Rails.application.secrets.GOOGLE_KEY
GOOGLE_SECRET = Rails.application.secrets.GOOGLE_SECRET
TWITTER_KEY = Rails.application.secrets.TWITTER_KEY
TWITTER_SECRET = Rails.application.secrets.TWITTER_SECRET
TWITTER_USERNAME = Rails.application.secrets.TWITTER_USERNAME
LINKEDIN_KEY = Rails.application.secrets.LINKEDIN_KEY
LINKEDIN_SECRET = Rails.application.secrets.LINKEDIN_SECRET
That's about it.
Rails.application.secrets.key_name
One way to do it is to store those secret keys in environment variables. How to set an environment variable is different depending on what operating system you're on. For a linux machine, usually you're editing a .bashrc or .bash_profile file in your home directory and adding a line that looks like:
export API_KEYS=apikeygoeshere
You'll have to edit the file for whatever user will run rails.
Then in production.rb, you can refer to those environment variables as:
ENV["API_KEYS"]
Another option is to use a ruby gem that essentially takes care of that for you, like figaro. The way it works is that you create another file that you don't check in and figaro takes care of setting them up as environment variables, which you can then refer to in your development.rb/production.rb scripts using the ENV["API_KEYS"] above. Because you aren't checking in the file that has all of the environment variables, you'll have to find some way to get that file onto whatever machines are running the code.
I know this question is specific to Rails 4.1, but those who upgrade to Rails 5.1 it now includes built in secret generation. Which seems a much better way to handle sensitive data in your rails app.
See: http://edgeguides.rubyonrails.org/5_1_release_notes.html#encrypted-secrets
A nice approach to deal with different environments would be to:
EDITOR=vim rails credentials:edit
development:
cloudinary:
cloud_name: dxe1hjkoi
api_key: 361019726125669
api_secret: Cn6tHfSf019278367sZoO083eOI
production:
cloudinary:
cloud_name: oiajsu98u
api_key: 091828812791872
api_secret: KJS98182kjaksh89721jhS9812j
Then use it as:
Cloudinary.config do |config|
config.cloud_name =
Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :cloud_name)
config.api_key =
Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :api_key)
config.api_secret =
Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :api_secret)
end

How to solve error "Missing `secret_key_base` for 'production' environment" (Rails 4.1)

I created a Rails application, using Rails 4.1, from scratch and I am facing a strange problem that I am not able to solve.
Every time I try to deploy my application on Heroku I get an error 500:
Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml`
The secret.yml file contains the following configuration:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
On Heroku I configured the "SECRET_KEY_BASE" environment variable with the result of the rake secret command. If I launch heroku config, I can see the variable with the correct name and value.
Why am I still getting this error?
I had the same problem and solved it by creating an environment variable to be loaded every time I logged in to the production server, and made a mini-guide of the steps to configure it:
I was using Rails 4.1 with Unicorn v4.8.2 and when I tried to deploy my application it didn't start properly and in the unicorn.log file I found this error message:
app error: Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml` (RuntimeError)
After some research I found out that Rails 4.1 changed the way to manage the secret_key, so if you read the secrets.yml file located at exampleRailsProject/config/secrets.yml you'll find something like this:
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
This means that Rails recommends you to use an environment variable for the secret_key_base in your production server. In order to solve this error you should follow these steps to create an environment variable for Linux (in my case Ubuntu) in your production server:
In the terminal of your production server execute:
$ RAILS_ENV=production rake secret
This returns a large string with letters and numbers. Copy that, which we will refer to that code as GENERATED_CODE.
Login to your server
If you login as the root user, find this file and edit it:
$ vi /etc/profile
Go to the bottom of the file using Shift+G (capital "G") in vi.
Write your environment variable with the GENERATED_CODE, pressing i to insert in vi. Be sure to be in a new line at the end of the file:
$ export SECRET_KEY_BASE=GENERATED_CODE
Save the changes and close the file using Esc and then ":x" and Enter for save and exit in vi.
But if you login as normal user, let's call it "example_user" for this gist, you will need to find one of these other files:
$ vi ~/.bash_profile
$ vi ~/.bash_login
$ vi ~/.profile
These files are in order of importance, which means that if you have the first file, then you wouldn't need to edit the others. If you found these two files in your directory ~/.bash_profile and ~/.profile you only will have to write in the first one ~/.bash_profile, because Linux will read only this one and the other will be ignored.
Then we go to the bottom of the file using Shift+G again and write the environment variable with our GENERATED_CODE using i again, and be sure add a new line at the end of the file:
$ export SECRET_KEY_BASE=GENERATED_CODE
Having written the code, save the changes and close the file using Esc again and ":x" and Enter to save and exit.
You can verify that our environment variable is properly set in Linux with this command:
$ printenv | grep SECRET_KEY_BASE
or with:
$ echo $SECRET_KEY_BASE
When you execute this command, if everything went ok, it will show you the GENERATED_CODE from before. Finally with all the configuration done you should be able to deploy without problems your Rails application with Unicorn or some other tool.
When you close your shell and login again to the production server you will have this environment variable set and ready to use it.
And that's it! I hope this mini-guide helps you solve this error.
Disclaimer: I'm not a Linux or Rails guru, so if you find something wrong or any error I will be glad to fix it.
I'm going to assume that you do not have your secrets.yml checked into source control (ie. it's in the .gitignore file). Even if this isn't your situation, it's what many other people viewing this question have done because they have their code exposed on Github and don't want their secret key floating around.
If it's not in source control, Heroku doesn't know about it. So Rails is looking for Rails.application.secrets.secret_key_base and it hasn't been set because Rails sets it by checking the secrets.yml file which doesn't exist. The simple workaround is to go into your config/environments/production.rb file and add the following line:
Rails.application.configure do
...
config.secret_key_base = ENV["SECRET_KEY_BASE"]
...
end
This tells your application to set the secret key using the environment variable instead of looking for it in secrets.yml. It would have saved me a lot of time to know this up front.
Add config/secrets.yml to version control and deploy again. You might need to remove a line from .gitignore so that you can commit the file.
I had this exact same issue and it just turned out that the boilerplate .gitignore Github created for my Rails application included config/secrets.yml.
This worked for me.
SSH into your production server and cd into your current directory, run bundle exec rake secret or rake secret, you will get a long string as an output, copy that string.
Now run sudo nano /etc/environment.
Paste at the bottom of the file
export SECRET_KEY_BASE=rake secret
ruby -e 'p ENV["SECRET_KEY_BASE"]'
Where rake secret is the string you just copied, paste that copied string in place of rake secret.
Restart the server and test by running echo $SECRET_KEY_BASE.
While you can use initializers like the other answers, the conventional Rails 4.1+ way is to use the config/secrets.yml. The reason for the Rails team to introduce this is beyond the scope of this answer but the TL;DR is that secret_token.rb conflates configuration and code as well as being a security risk since the token is checked into source control history and the only system that needs to know the production secret token is the production infrastructure.
You should add this file to .gitignore much like you wouldn't add config/database.yml to source control either.
Referencing Heroku's own code for setting up config/database.yml from DATABASE_URL in their Buildpack for Ruby, I ended up forking their repo and modified it to create config/secrets.yml from SECRETS_KEY_BASE environment variable.
Since this feature was introduced in Rails 4.1, I felt it was appropriate to edit ./lib/language_pack/rails41.rb and add this functionality.
The following is the snippet from the modified buildpack I created at my company:
class LanguagePack::Rails41 < LanguagePack::Rails4
# ...
def compile
instrument "rails41.compile" do
super
allow_git do
create_secrets_yml
end
end
end
# ...
# writes ERB based secrets.yml for Rails 4.1+
def create_secrets_yml
instrument 'ruby.create_secrets_yml' do
log("create_secrets_yml") do
return unless File.directory?("config")
topic("Writing config/secrets.yml to read from SECRET_KEY_BASE")
File.open("config/secrets.yml", "w") do |file|
file.puts <<-SECRETS_YML
<%
raise "No RACK_ENV or RAILS_ENV found" unless ENV["RAILS_ENV"] || ENV["RACK_ENV"]
%>
<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
SECRETS_YML
end
end
end
end
# ...
end
You can of course extend this code to add other secrets (e.g. third party API keys, etc.) to be read off of your environment variable:
...
<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
third_party_api_key: <%= ENV["THIRD_PARTY_API"] %>
This way, you can access this secret in a very standard way:
Rails.application.secrets.third_party_api_key
Before redeploying your app, be sure to set your environment variable first:
Then add your modified buildpack (or you're more than welcome to link to mine) to your Heroku app (see Heroku's documentation) and redeploy your app.
The buildpack will automatically create your config/secrets.yml from your environment variable as part of the dyno build process every time you git push to Heroku.
EDIT: Heroku's own documentation suggests creating config/secrets.yml to read from the environment variable but this implies you should check this file into source control. In my case, this doesn't work well since I have hardcoded secrets for development and testing environments that I'd rather not check in.
You can export the secret keys to as environment variables on the ~/.bashrc or ~/.bash_profile of your server:
export SECRET_KEY_BASE = "YOUR_SECRET_KEY"
And then, you can source your .bashrc or .bash_profile:
source ~/.bashrc
source ~/.bash_profile
Never commit your secrets.yml
For rails6, I was facing the same problem as I was missing the following files. Once I added them the issue was resolved:
1. config/master.key
2. config/credentials.yml.enc
Make sure you have these files!
What I did :
On my production server, I create a config file (confthin.yml) for Thin (I'm using it) and add the following information :
environment: production
user: www-data
group: www-data
SECRET_KEY_BASE: mysecretkeyproduction
I then launch the app with
thin start -C /whereeveristhefieonprod/configthin.yml
Work like a charm and then no need to have the secret key on version control
Hope it could help, but I'm sure the same thing could be done with Unicorn and others.
I have a patch that I've used in a Rails 4.1 app to let me continue using the legacy key generator (and hence backwards session compatibility with Rails 3), by allowing the secret_key_base to be blank.
Rails::Application.class_eval do
# the key_generator will then use ActiveSupport::LegacyKeyGenerator.new(config.secret_token)
fail "I'm sorry, Dave, there's no :validate_secret_key_config!" unless instance_method(:validate_secret_key_config!)
def validate_secret_key_config! #:nodoc:
config.secret_token = secrets.secret_token
if config.secret_token.blank?
raise "Missing `secret_token` for '#{Rails.env}' environment, set this value in `config/secrets.yml`"
end
end
end
I've since reformatted the patch are submitted it to Rails as a Pull Request
I've created config/initializers/secret_key.rb file and I wrote only following line of code:
Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]
But I think that solution posted by #Erik Trautman is more elegant ;)
Edit:
Oh, and finally I found this advice on Heroku: https://devcenter.heroku.com/changelog-items/426 :)
Enjoy!
this is works good https://gist.github.com/pablosalgadom/4d75f30517edc6230a67
for root user should edit
$ /etc/profile
but if you non root should put the generate code in the following
$ ~/.bash_profile
$ ~/.bash_login
$ ~/.profile
On Nginx/Passenger/Ruby (2.4)/Rails (5.1.1) nothing else worked except:
passenger_env_var in /etc/nginx/sites-available/default in the server block.
Source: https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_env_var
Demi Magus answer worked for me until Rails 5.
On Apache2/Passenger/Ruby (2.4)/Rails (5.1.6), I had to put
export SECRET_KEY_BASE=GENERATED_CODE
from Demi Magus answer in /etc/apache2/envvars, cause /etc/profile seems to be ignored.
Source: https://www.phusionpassenger.com/library/indepth/environment_variables.html#apache
In my case, the problem was that config/master.key was not in version control, and I had created the project on a different computer.
The default .gitignore that Rails creates excludes this file. Since it's impossible to deploy without having this file, it needs to be in version control, in order to be able to deploy from any team member's computer.
Solution: remove the config/master.key line from .gitignore, commit the file from the computer where the project was created, and now you can git pull on the other computer and deploy from it.
People are saying not to commit some of these files to version control, without offering an alternative solution. As long as you're not working on an open source project, I see no reason not to commit everything that's required to run the project, including credentials.
I had the same problem after I used the .gitignore file from https://github.com/github/gitignore/blob/master/Rails.gitignore
Everything worked out fine after I commented the following lines in the .gitignore file.
config/initializers/secret_token.rb
config/secrets.yml

Making ENV variables accessible in development

When storing sensitive credentials I normally create a yml file and load it like so in my development.rb
APP_CONFIG = YAML.load_file("#{Rails.root}/config/config.yml")[Rails.env]
I can then access like so
APP_CONFIG["google_secret"]
Problem is Heroku doesn't like this so i need to set ENV variables locally to make integration easier. so i have created a env.rb file like so
ENV['google_key'] = 'xxx'
ENV['google_secret'] = 'xxx'
ENV['application_key'] = 'xxx'
and to accesss it i thought i could use
x = ENV['application_key']
But its not finding the variable, how do I load them in the development environment?
Thanks
You should put the env.rb file in initializers folder. You can add env.rb file to .gitignore file if you don't want to push it to heroku.
Have you considered using Figaro to do this? Figaro was inspired by Heroku's secret key application configuration, so it's really easy to make secret ENV variables in development accessible in Heroku production environments.
I wrote up an answer on this StackOverflow thread about hiding secret info in Rails (using Figaro) that can hopefully serve of some reference to you as well.

Resources