Rails on Heroku: git add environment.rb or not? - ruby-on-rails

I usually git-ignore config/environment.rb file. I add ENV['RAILS_ENV'] setting into that file so it should be different on different machine.
However, Heroku requires that file in git. Without it, the application crashes.
How do you handle it?
Thanks.
Sam

You shouldn't ignore config/environment.rb. As Zeke already answered, you can set environment variables in a live Heroku app.
To see a list of environment variables available to your heroku app run heroku config. To set the value of an specific variable run heroku config:add RAILS_ENV=staging --app yourapp.
But what about your development app running in your own machine? There are some options, one is exporting an environment variable in your shell:
$ export RAILS_ENV=staging
$ echo $RAILS_ENV
staging
But I prefer another approach. This is what I have in my config/environment.rb:
# Load the rails application
require File.expand_path('../application', __FILE__)
# Load environment vars from local file
env_vars = File.join(Rails.root.to_s, 'config', 'env_vars.rb')
load(env_vars) if File.exists?(env_vars)
# Initialize the rails application
MyApp::Application.initialize!
If there is a config/env_vars.rb file, it will be loaded. This is the contents of a sample env_vars.rb file:
ENV["REDISTOGO_URL"] = 'redis://localhost:6379'
ENV["AWS_ACCESS_KEY"] = '283983483'
ENV["AWS_SECRET"] = '743843934'
ENV["S3_BUCKET"] = 'myapp-development'
This way you could have different sets of environment variables for your development, staging and production apps.
You will want to git-ignore this file.
While I'm running my development app I want to send files to a myapp-development S3 bucket. But I want my production app (in Heroku) to send files to a myapp-production S3 bucket.
$ heroku config:add S3_BUCKET='myapp-production' --app myapp
And a different bucket for my staging app (also running in Heroku):
$ heroku config:add S3_BUCKET='myapp-staging' --app myapp-staging
Since you'll git-ignore config/env_vars.rb, it will not be present in your apps running in Heroku, and so they'll get their environment variables from the above heroku config:add configurations.
Since I work with other people, I often include an example env_vars.rb.example file in the project, which is not ignored by git:
File config/env_vars.rb.example:
# Copy this file to config/env_vars.rb
# MAKE SURE THAT YOUR .gitignore INCLUDES IT!
#
# This file is used to set environment variables that would be present on
# Heroku, and are needed for our development and test instances to run.
ENV["REDISTOGO_URL"] = 'redis://localhost:6379'
ENV["AWS_ACCESS_KEY"] = 'xxx'
ENV["AWS_SECRET"] = 'xxx'
ENV["S3_BUCKET"] = 'some-bucket'
if Rails.env.test?
HOST = "example.com"
else
HOST = "development.intranet"
end
Notice that an advantage of loading this env_vars.rb file is that you can do different things programmatically, for example setting the HOST constant to a different value if you are running your tests, like above.

Heroku has pretty great documentation. To answer your question directly, they provide and interface to configure environment variables. They even provide a mechanism that makes deploying to two+ Heroku-hosted apps with different environments quite easy.

Related

Are there any reasons not to use RAILS_ENV=staging on Heroku?

The Heroku documentation at https://devcenter.heroku.com/articles/deploying-to-a-custom-rails-environment says I shouldn't use a staging.rb file to define my staging environment.
It may be tempting to create another custom environment such as “staging” and create a config/environments/staging.rb and deploy to a Heroku app with RAILS_ENV=staging.
This is not a good practice. Instead we recommend always running in production mode and modifying any behavior by setting your config vars.
I think this is terrible advice and conflicts with well-established Rails best practice. However, I'm not here to argue about best practices. I'm here to ask:
Are there any reasons not to use RAILS_ENV=staging on Heroku?
Is there anything that will break if I create a staging.rb file and set the xxx_ENV config vars like this?
heroku config:add RACK_ENV=staging --remote staging
heroku config:add RAILS_ENV=staging --remote staging
No, there isn't anything that will break if you do this.
However, I do think that Heroku is right here (note that I work at Heroku).
It introduces possible differences between your staging and production environments, when the only thing that changes between them should be configuration variables.
Heroku already provides a secure mean of setting configuration variables, with the config:set command.
Using 2 config files means you have to maintain the same configuration twice, and possible can have issues because you updated the configuration correctly in staging, but incorrectly in production.
As a side note, RACK_ENV should only ever have 3 values: production, development and none. See https://www.hezmatt.org/~mpalmer/blog/2013/10/13/rack_env-its-not-for-you.html
You'll get some warnings from Heroku when you deploy, but I can confirm I did run staging apps, with RAILS_ENV=staging, on Heroku. As long as you set the correct environment variables and Gemfile groups, it should just work.
My guess is that the reason they advise not to use custom environments is that they have some operational tooling that assumes your Rails app runs in production environment, but so far I didn't run into issues.

Heroku S3 Env variables

I'm trying to use carrierwave to upload images to S3. It works locally but when I go to deploy to heroku I get the following error:
ArgumentError: Missing required arguments: aws_access_key_id, aws_secret_
access_key
The keys are definitely set because I can see them when I run heroku:config
I've searched every answer I could find on stack and I searched through every answer on the first 3 pages of Google. None of them have worked.
I know the uploading works so it's not the code that's a problem. What settings or variables do I have to set to make this work?
Please help, I can't move forward with my app until this is done (so I can deploy to heroku again without it being stopped because of this error.)
Some info:
Environment Variables
You've got a problem with the calling of your environment variables in
Heroku. ENV vars are basically variables stored in the OS /
environment, which means you've got to set them for each environment
you attempt to your deploy application
heroku config should should the ENV vars you've set. If you don't see ENV['AWS_ACCESS_KEY'] etc, it means you've not set them correctly, which as explained is as simple as calling the command heroku config:add YOUR_ENV_VAR=VAR
Figaro
I wanted to recommend using Figaro for this
This is a gem which basically stores local ENV vars in config/application.yml. This allows you to store ENV variables locally; but more importantly, allows you to sync them with Heroku using this command:
rake figaro:heroku
This will set your env vars on Heroku, allowing you to use them with Carrierwave as recommended in the other answers
It sounds like you have set the ENV variables on Heroku, but you need to hook those up to CarrierWave.
In config/initializers/fog.rb
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => Rails.configuration.s3_access_key_id,
:aws_secret_access_key => Rails.configuration.s3_secret_access_key,
}
end
In your environments/<environment>.rb file
Rails.application.configure do
config.s3_access_key_id = ENV['S3_ACCESS_KEY_ID']
config.s3_secret_access_key = ENV['S3_SECRET_ACCESS_KEY']
end
This sets your Rails config to the ENV variables on Heroku which makes them available as Rails.configuration.<key>

Rails ENV Variables

I have recently asked a similar question to this but as the problem has moved on slighty I have decided to create a new question - I hope this is the expected approach?
Having pushed my Rails 4 app to Heroku I keep getting an Internal Server Error Page and the error is:
You must set config.secret_key_base in your app's config
This is happening because my .gitignore file includes the config/initializers/secret_token.rb deliberately.
I have installed the Figaro gem so that I could set my secret_key_base as an environment variable for added security. I have checked on Heroku that the key has been set correctly.
My code for the secret_token.rb is as follows:
MyApp::Application.config.secret_key_base = ENV["SECRET_KEY_BASE"]
However, I'm still getting the same issue.
Can anyone help???
I did something simlilar to you that worked, but didn't use Figaro. I based it off this blog post
In summary, here's what I did:
1) remove config/initializers/secret_token.rb from your .gitignore
2) Use this code for your secret_token.rb:
MyApp::Application.config.secret_token = if Rails.env.development? or Rails.env.test?
('x' * 30) # meets minimum requirement of 30 chars long
else
ENV['SECRET_TOKEN']
end
3) commit and re-push
4) set Heroku env variale like:
heroku config:set SECRET_TOKEN=12345.....
Worked as soon as Heroku restarted after the config set.
You can set environment variables on heroku:
https://devcenter.heroku.com/articles/config-vars
You need to set SECRET_KEY_BASE environment variable for heroku with this command:
heroku config:set SECRET_KEY_BASE=value
This may help folks using Rails +4.1:
"When deploying a Rails 4.1+ app, Heroku will specify a SECRET_KEY_BASE on
your app by default." (https://blog.heroku.com/container_ready_rails_5)
In other words you won't have to do anything. You can omit secrets.yml (the standard version that is) from your .gitignore file without fear of losing any production related secrets.

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.

ROR deployment: Staging and Development environments

I already have a production instance deployed on the server. Its working well.
Here is what I need to do.
Deploy a staging and Development environment on the server.
I have already created a branch in github to do that.
Config
1) Ruby 1.8.6
2) Rails is being vendored
3) Webserver Nginx and Thin
4) I have already create a file under /usr/local/nginx/sites-enabled and sites-available folders
5) Added yml file under /etc/thin
6) Made edits to the deploy.rb and have added dev.rb under the config and deploy folders
7) Capistrano is being used on the server for deploy
Questions:
How to deploy the dev environment from separate github branch different that production ? Will that reboot/affect the current production environment too ?
I want to make sure the production wont get affected by this. Please provide a list of commands
or tutorials that will help me with this. I am into very early stages of of learning ROR so please be
a little details. Help is very much appreciated.
EDIT:
1) Capify the project by installing the gem locally and running capify locally.
2) Make changes to you deploy.rb under config
3) set :stages with staging and production
4) set :default_stage as staging .. You have to edit this file more to customize your deployment
5) Under config/deploy/ : Create you production and staging ".rb" files. set the branch to master or any specific branch. Set your rails_env to staging in staging.rb and to production in production.rb.
Set deploy_to as xxxpath/staging and xxxpath/production in those appropriate files.
6) cap deploy will deploy in staging as default due to 4)
7) cap production deploy for production
It looks like you're most of the way there. The key will be to ensure that Capistrano deploys each branch to a separate location on the filesystem -- the sites-available document roots should be different (in other words, don't overwrite your production files!).
Two methods, if you have set stable production, staging and development branches, use the method documented here http://help.github.com/deploy-with-capistrano/
You can use this method for one-off branch deployments Using capistrano to deploy from different git branches.
Passenger looks for the file tmp/restart.txt to know when to restart; this is under the application tree so should only affect the specific variant of the site.
Depending on your server's capacity, the production site may suffer a brief performance hit from the restart of another environment. When you are able, you should consider getting a separate server for staging, test, dev, etc.

Resources