Set SECRET_KEY_BASE in production using a .env file - ruby-on-rails

I've a .env file in my root folder in production. This file defines SECRET_KEY_BASE which is used in config/secrets.yml. The problem is that I can't manage to load my .env file before my config/secrets.yml. I've tried using the dotenv gem without success.
Any idea on how todo this in production?
I don't want to set it globally for my webmaster user on the production server. The SECRET_KEY_BASE value should only be accessable for by application.
I'm using rails 4.1.

I too use dotenv gem. It works for me in almost all case.
This is my configuration of dotenv gem (yes, i put dotenv in Gemfile). I just create an aaaaa.rb initializer file.
config/initializers/aaaaaa.rb
#obscure name because rails load initializers/* files based on alphabets
require 'dotenv'
Dotenv.load
And, cases which it doesn't, i do this this finally in config/boot.rb file
ENV["SECRET_KEY_BASE"] = "foobar"

I was also having this problem. Here is how I got it to work. I followed documentation to initialize dotenv early:
# config/application.rb
Bundler.require(*Rails.groups)
Dotenv::Railtie.load
HOSTNAME = ENV['HOSTNAME']
But then I came across this error (issue #155):
gems/dotenv-rails-1.0.2/lib/dotenv/rails.rb:17:in `load': undefined method `join' for nil:NilClass (NoMethodError)
The workaround (also documented in issue #155) is to replace Dotenv::Railtie.load with:
Dotenv.load(File.expand_path("../../.env.#{Rails.env}", __FILE__))
Apparently this is only a problem when using rails 4.1.

Was also having this problem, but manage to get it to work by having this in my secrets.yml file:
production:
secret_key_base: ENV["SECRET_KEY_BASE"]
It worked after removing the <%= %>

Related

Figaro Environment Variables in Gemfile

I'm trying to set an auth token for my gemfile to access a private git repo.
i.e.
gem 'mygem', git: "https://ENV['GITHUB_AUTH_TOKEN']:x-oauth-basic#github.com/my_account/my_repo.git", tag: "0.0.1"
I can't work out how to store this in Figaro but make it accessible to bundle when I run bundle install.
Very similar to
This question
Except that rather than having a config/heroku_env.rb I have an config/application.yml file.
I'm sure the answer is ridiculously straightforward.
I'd like to keep it in that file as it keeps everything neatly in one place, but if not I can put it somewhere specific so long as it lines up with heroku nicely.
Any ideas?
I have found one way to do it that works, it's slightly annoying in that you have to keep the credentials in two different places.
.bundle
BUNDLE_GITHUB__COM: <auth_token>:x-oauth-basic
Gemfile
gem 'mygem', git: "https://github.com/my_account/my_repo.git", tag: "0.0.1"
# Note that you don't put anything in here, bundler sorts it out automagically
And then
heroku config:set BUNDLE_GITHUB__COM=<auth_token>:x-oauth-basic
Works.
Annoying because now application.yml has different content to my heroku file. But so be it.
Update:
Better solution
Just put
BUNDLE_GITHUB__COM: <auth_token>:x-oauth-basic
into both your application.yml and heroku config.
I wish someone had documented that somewhere, would have saved me a ton of trouble...
I think you need to run
figaro heroku:set -e production
for it to set set the environment variables in your config/application.yml file as Heroku environment variables.

Rails require statements in environment config files

In my config\environments\development.rb and config\environments\production.rb files, I set some global variables. In the example below, I have a a Redis instance that points to our cache, and a Statsd instance that points to the DataDog agent.
config.x.cache = Redis.new(url: ENV["CACHE"])
config.x.statsd = Statsd.new('localhost', 8125)
In the case of Redis, I added gem 'redis' to my gem file, ran bundle install and everything worked fine. In the case of StatsD, however, it seems that I need to also add require 'statsd' at the top of the development.rb and production.rb files in order to be able to create the instance. Of course, I also added gem 'dogstatsd-ruby' to my gem file and ran bundle install, but that didn't seem to be enough. If I don't add the require statement at the top of the config files, I get the following error when I try to run my Rails app:
uninitialized constant Statsd (NameError)
Can anyone explain why I have to add the require statement only in this particular case (StatsD), or is there is a better way to do this? Thanks!

.env not being loaded in test environment in Rails with rspec

I am using gem 'dotenv-rails', '~> 0.9.0' to load environment variables into a Rails 4.0.5 app. I have a .env file along with a .env.test. All is working well in development, however when it comes to testing, which I do with rspec, it is failing to set the environment variables.
I have gone into Rails console in testing environment and I can see they are set to nil.
Any tips on how to get dotenv to load in testing?
This is a late answer, but for anyone who may find it helpful, add this to spec_helper.rb
require 'dotenv'
Dotenv.load('.env')
Also, Dotenv.load can accept a list, for example:
Dotenv.load(
'.env.local',
'.env.test',
'.env'
)
If you have test specific environemnt config, You can use Dotenv.overload to overwrite other env config. Just add the following to your spec_helper.rb or rails_helper.rb.
require "dotenv"
Dotenv.overload ".env.test"
Dotenv.overload ".env.test.local"
Dotenv.load(File.expand_path("../../.env.#{Rails.env}", __FILE__))
upon researching Paritosh's answer I found that the file needed to specified per environment.
put this line in Dotenv::Railtie.load in rspec setting or any page in which you want to load dot env file.

Error with Oauth token not redirect

Basically, I can't find my production ID and my production API secret. I can only find the developer ones. Am I supposed to submit for review first? My OAuth is all set up.
I also have my YML So do I submit first and I will get this second ID? This has been my problem all day long. Thanks.
It looks like this:
Development:
facebook_api_key:
facebook_api_secret:
Production:
facebook_api_key:
facebook_api_secret:
I tried adding my ID and secret for both of them even though it was only on dev! Please help me!
Actually, your problem has nothing to do with oauth. It is about how to setup secret variables between different environments.
I use figaro gem to handle this kind of variables:
First, add figaro in your Gemfile.
Gemfile
gem 'figaro'
Setup variables in config/applicaiton.yml. (I usually use UPPER CASE for these variables)
config/application.yml
development:
FB_KEY: your_fb_key_for_development
FB_SECRET: your_fb_secret_for_development
production:
FB_KEY: your_fb_key_for_production
FB_SECRET: your_fb_secret_for_production
And use ENV to get variables where you want,
config/initializers/devise.rb
Devise.setup do |config|
# ...
# Onmi configurations
require "omniauth-facebook"
config.omniauth :facebook, ENV['FB_KEY'], ENV['FB_SECRET']
# ...
end
If you want to do it without any gem, please see:
stackoverflow - Setting Environment Variables in Rails 3 (Devise + Omniauth)

Using config/secrets.yml in Rails 4.0.2 version

I was reading http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html
and saw there the trick with config/secrets.yml
I moved my secret_base_keys to that file, and removed secret_token.rb file.
But server doesn't start.
DEPRECATION WARNING: You didn't set config.secret_key_base. Read the upgrade documentation to learn more about this new config option. (called from service at /home/bismailov/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/1.9.1/webrick/httpserver.rb:138)
[2014-01-15 16:15:51] ERROR RuntimeError: You must set config.secret_key_base in your app's config.
I believe that is because I don't use Rails 4.1 yet.
Is there any way to implement this new functionality (secrets.yml) in Rails version 4.0? Maybe some kind of gem...
Thank you very much!
This secret_key_base deprecation does not seem to have alternative syntax to remove the deprecation warning in a Rails 4.0 application. To satisfy the deprecation, follow the steps for moving the production key to secrets.yml and delete the secret_token.rb file. The implement a YAML loader in your application.rb to extract the token from your secrets.yml file.
Use rake secret to generate a new token for each of your environments. Copy and paste the output to each section of your secrets.yml file.
# config/secrets.yml
development:
secret_key_base: __pasted from rake secret___
test:
secret_key_base: __pasted from rake secret___
production:
secret_key_base: __pasted token from config/initializers/secret_token.rb___
# config/application.rb
# TODO Remove this in Rails 4.1
config.secret_key_base = YAML.load(File.open("#{Rails.root}/config/secrets.yml"))[Rails.env]['secret_key_base']
Cite: https://github.com/rails/rails/pull/13298
UPDATE:
My original post focused on Inspired by #user2998870, I added a method to my application.rb that is allows one to implement multiple secrets, not just secret_key_base. This makes top-level keys accessible as methods e.g. Rails.application.secrets.braintree_merchant_id.
If nested, one can call the nested key value using Rails.application.secrets.braintree['merchant_key'].
Note: The original code above is still needed for secret_key_base to operate correctly in Rails 4.0.
# config/application.rb
def secrets
#secrets ||= begin
yaml = YAML.load(File.open("#{Rails.root}/config/secrets.yml"))[Rails.env]
ActiveSupport::OrderedOptions.new.merge!(yaml.symbolize_keys)
end
end
config/secrets.yml is a feature of Rails 4.1. Upgrade to Rails 4.1 to use the feature.
I did like #scarver2 mentioned, but I did it by borrowing some code from Rails 4.1 (I'm currently using on 4.0.3)
# Load 3rd party service passwords from config/services.rb.
# This is patch code to support config/services.rb till we upgrade to Rails 4.1.
# TODO: Remove this section after upgrading to Rails 4.1.
# Borrowed from rails/railties/lib/rails/application/configuration.rb
config.paths.add "config/secrets", with: "config/secrets.yml"
# Borrowed from rails/railties/lib/rails/application.rb
def secrets #:nodoc:
#secrets ||= begin
secrets = ActiveSupport::OrderedOptions.new
yaml = config.paths["config/secrets"].first
if File.exist?(yaml)
require "erb"
all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {}
env_secrets = all_secrets[Rails.env]
secrets.merge!(env_secrets.symbolize_keys) if env_secrets
end
# Fallback to config.secret_key_base if secrets.secret_key_base isn't set
secrets.secret_key_base ||= config.secret_key_base
secrets
end
end

Resources