Heroku S3 Env variables - ruby-on-rails

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>

Related

getting error on production related to config.yml

I am trying to push a app on heroku, Its gets pushed but none of my assets gets uploaded on heroku.
Its works all good locally. So I check with rails s -e --production and It gives me error in secrets.yml
It says
Missing secret_token and secret_key_base for '--production' environment, set these values in config/secrets.yml
I am not sure what It is. Please help..
I believe that for a heroku app to run in production Rails expects the secret configuration to exist. Remove the line within your .gitignore that prevents secrets.yml from updating within version control and then make sure you use ENV variables for your secret tokens. If you don't have any secret tokens that aren't just tests then you shouldn't have to worry about it, but if you do you can use gems like figaro to configure your Environment variables that will keep your tokens off VCM.
Edit: If you look within your config directory you should see a secrets.yml that was generated with your app. Within the app you should see your secret_key_base variables within dev, test, and production. Within production though you should have:
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> <- This being your Environment variable

Refresh .bashrc with new env variables

I have a production server running our rails app, and we have ENV variables in there, formatted correctly. They show up in rails c but we have an issue getting them to be recognized in the instance of the app.
Running puma, nginx on an ubuntu box.
What needs to be restarted every time we change .bashrc? This is what we do:
1. Edit .bashrc
2. . .bashrc
3. Restart puma
4. Restart nginx
still not recognized..but in rails c, what are we missing?
edit:
Added env variables to /etc/environment based on suggestions from other posts saying that .bashrc is only for specific shell sessions, and this could have an effect. supposedly /etc/environment is available for all users, so this is mine. still having the same issues:
Show up fine in rails c
Show up fine when I echo them in shell
Do not show up in application
export G_DOMAIN=sandboxbaa3b9cca599ff0.mailgun.org
export G_EMAIL=mailgun#sandboxbaa3ba3806d5b499ff0.mailgun.org
export GEL=support#xxxxxx.com
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
edit:
In the app i request G_DOMAIN and G_EMAIL in plain html (this works on development with dotenv, does not work once pushed to production server with ubuntu server) :
ENV TEST<BR>
G_DOMAIN: <%= ENV['G_DOMAIN'] %><br>
G_EMAIL:<%= ENV['G_EMAIL'] %>
However, the following env variables are available to use (in both .bashrc and /etc/environment, same as all variables we displayed above) because our images work fine and upload to s3 with no issue, on production.
production.rb
# Configuration for Amazon S3
:provider => 'AWS',
:aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
edit2: could this be anything with this puma issue?
https://github.com/puma/puma/commit/a0ba9f1c8342c9a66c36f39e99aeaabf830b741c
I was having a problem like this, also. For me, this only happens when I add a new environment variable.
Through this post and after some more googling, I've come to understand that the restart command for Puma (via the gem capistrano-puma) might not see new environment variables because the process forks itself when restarting rather than killing itself and being started again (this is a part of keeping the servers responsive during a deploy).
The linked post suggests using a YAML file that's only stored on your production server (read: NOT in source control) rather than rely on your deploy user's environment variables. This is how you can achieve it:
Insert this code in your Rails app's config/application.rb file:
config.before_configuration do
env_file = File.join(Rails.root, 'config', 'local_env.yml')
YAML.load(File.open(env_file)).each do |key, value|
ENV[key.to_s] = value
end if File.exists?(env_file)
end
Add this code to your Capistrano deploy script (config/deploy.rb)
desc "Link shared files"
task :symlink_config_files do
on roles(:app) do
symlinks = {
"#{shared_path}/config/local_env.yml" => "#{release_path}/config/local_env.yml"
}
execute symlinks.map{|from, to| "ln -nfs #{from} #{to}"}.join(" && ")
end
end
before 'deploy:assets:precompile', :symlink_config_files
Profit! With the code from 1, your Rails application will load any keys you define in your server's Capistrano directory's ./shared/config/local_env.yml file into the ENV hash, and this will happen before the other config files like secrets.yml or database.yml are loaded. The code in 2 makes sure that the file in ./shared/config/ on your server is symlinked to current/config/ (where the code in 1 expects it to be) on every deploy.
Example local_env.yml:
SECRET_API_KEY_DONT_TELL: 12345abc6789
OTHER_SECRET_SHH: hello
Example secrets.yml:
production:
secret_api_key: <%= ENV["SECRET_API_KEY_DONT_TELL"] %>
other_secret: <%= ENV["OTHER_SECRET_SHH"] %>
This will guarantee that your environment variables are found, by not really using environment variables. Seems like a workaround, but basically we're just using the ENV object as a convenient global variable.
(the capistrano syntax might be a bit old, but what is here works for me in Rails 5... but I did have to update a couple things from the linked post to get it to work for me & I'm new to using capistrano. Edits welcome)

capistrano environment variables are not used in rails code

I am using capistrano to deploy a rails application. To set up email using sendgrid I need to setup environment variables.
I have used
set :default_environment, {
'SENDGRID_USERNAME' => "username",
'SENDGRID_PASSWORD' => 'password',
}
checking with
cap shell
cap > printenv
I can see the environment variables being set correctly.
However the app running through unicorn cannot see these variables, as the sending of email fails with SMTP authentication error.
I have also tried to source a file containing the exports using capistrano
run . app/shared/config/env
But environment variables are still not set
The development environment works fine, so I know the smtp credentials are ok.
How to set environment variables correctly so that the app can see them?
I don't know how to do it using Capistrano, but you can try Figaro gem.

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.

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

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.

Resources