Load environment variable in boot file - ruby-on-rails

I am facing issue while loading envrionment variable in boot.rb. I tried with 2 gems dotenv & dotenv-rails but none of them worked for me. Other places I am able to use environment variable but not in boot.rb. Anyone have any clue on this one
if ["development"].include?(ENV['RAILS_ENV'])
require 'bootsnap/setup'
Bootsnap.setup(
cache_dir: 'tmp/cache', # Path to your cache
development_mode: 'development', # Current working environment, e.g. RACK_ENV, RAILS_ENV, etc
load_path_cache: true, # Optimize the LOAD_PATH with a cache
autoload_paths_cache: true, # Optimize ActiveSupport autoloads with cache
compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
compile_cache_yaml: true # Compile YAML into a cache
)
end

DotEnv will only load your .env file into env once the Gem has been loaded.
In Rails this is done by the line Bundler.require(*Rails.groups) in config/application.rb. If you need to access the env vars before that you need to manually call Dotenv::Railtie.load:
Bundler.require(*Rails.groups)
Dotenv::Railtie.load
Or at least thats what the readme would lead you to belive. Instead of the Railtie I guess you could use the plain ruby approach:
require 'dotenv'
Dotenv.load
But there are tons options to set ENV vars from a file such as direnv which is not a Ruby gem and hooks into your shell itself.

You could use - depending on your needs - a load or require to explicitly process your .env file, before testing the environment variable.

Related

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!

Multiple environments for Ruby application

I've been writing Rails apps for so long that I'm suddenly stuck with something you get for free with Rails: environments.
That is to say, you can run the Rails app locally and by default, RAILS_ENV (or Rails.env) is "development". And if you are running your specs/tests, it's "test" and when you deploy to your production server, you set it up to run as "production".
This is particularly useful when you have config files. Also useful for the Gemfile to differentiate gems for certain environments.
So now to my question: I'm writing a pure Ruby app and I don't know the best way to set it up so that I can still have the multiple environments? I want to set up config files for 3rd-party services (like MongoLab/Iron.IO/etc.) but I want them set up with "development", "test", "production", etc. And then I want to be able to run the app from various environments.
I know I could just manually handle it via command-line environment variables, but I'm wondering if there are best (better?) practices for this? Any gems that help with this? Or any recommendations for how to structure environment handling for a pure Ruby app?
Thanks,
You could do something quite like the way rails does it:
class AppEnvironment
def initialize(env = :production)
#name = env.intern
end
def development?
#name == :development
end
def test?
#name == :test
end
def production?
#name == :production
end
end
app_environment = AppEnvironment.new( ENV['APP_ENVIRONMENT'] )
Then you set the environment var via rake tasks.
namespace :myapp do
desc "Run a development server"
task :server => :environment do
ENV['APP_ENVIRONMENT'] ||= "development"
# ...
end
desc "Run a bunch of tests"
task :test => :environment do
ENV['APP_ENVIRONMENT'] ||= "test"
# alternatively do this in `spec_helper.rb`
end
end
Added.
Using different sets of gems per environment is pretty easy with Bundler.
You might recognize this line from config/application.rb in rails:
Bundler.require(:default, Rails.env) # Rails.env is just a string
This tells bundler to require all gems in a specific group in addition to gems declared outside a group.
gem 'foo'
group :test do
gem 'rspec'
end
If you are just talking about config files, you can just use a setup that looks like Rail's database.yml file, read it in and select the "right" set of variables.
There is also at least one gem to deal with such "multi-level" config files.
Use ENV['RACK_ENV']. RAILS_ENV is actually just a copy of it.
Use other ENV's to manage your dependencies. For example, credentials and configs can be stored in ENV's.
Some ENV's are typically stored in a config file, like database.yml or mongoid.yml.
You can use the dotenv gem to manage your local ENV's. However, I prefer to have a Ruby or shell script that sets the ENV's and/or starts the server in development environment:
local_setup.rb:
ENV[ 'RACK_ENV' ] = 'development'
or
rackup_local.sh:
RACK_ENV=development rackup
You can use a similar script for the test config and require it in the spec helper. I prefer to add the configs to the top of the spec helper.
If you put secrets in your env script, be sure to Git ignore it and do not add it to your repo.
Regarding the Gemfile, it is not a good idea to use different gems for different environments unless there is a good reason to do so. Testing, debugging and caching are good examples for being in an environment group in the Gemfile.

.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.

Set SECRET_KEY_BASE in production using a .env file

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 <%= %>

Confused by RVM's instructions for Capistrano

Working to get RVM working with Capistrano and Rails 3.1rc5 and confused by the instructions I found.
RVM's website provides these instructions that say:
In the new option, you can do the following (adjust to your personal setup):
$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # Add RVM's lib directory to the load path.
require "rvm/capistrano" # Load RVM's capistrano plugin.
set :rvm_ruby_string, 'ree#rails3' # Or whatever env you want it to run in.
Now I assume they want this at the top of our deploy.rb file!?! I only ask because I've not seen a "$:." in the, albeit few, deploy.rb's that I've seen.
What does the line starting with "$:." do exactly? And does it belong in deploy.rb or somewhere else?
$: is a special Ruby variable that is equivalent to $LOAD_PATH, which is the path that Ruby searches whenever you use a require statement. Calling .unshift(...) on it adds the provided path to the front of the load path.
If you just called require 'rvm/capistrano' without the $:.unshift statement, you would get an error, because by default, RVM's Capistrano library is not in Ruby's load path. The reason you haven't seen this in other deploy.rb files is because typically, the only libraries that are needed are Capistrano's, which are already included by running cap deploy (or any of the other cap commands).
My deploy.rb files have this exact same code in them and it works great.
I believe this needs to be at the top level, so that it gets set before any calls--i.e. before bundle, any rake tasks, etc. This has been problematic for me. In my case, my web and app servers are not the same, and I do not want rvm on the web server.
It also seems a little black magic, when the real solution is rather easy. After updating your code, set up a blessed gemset in an .rvmrc file, and nothing else needs to be done.
after "deploy:update_code", "deploy:rvm:setup"
namespace :deploy do
namespace :rvm do
# Set up .rvmrc
# Note, not using method described in:
# https://rvm.beginrescueend.com/integration/capistrano/
# We want to use RVM only on the app server, so better to set up and bless an .rvmrc file
task :setup, :roles => :app do
run "cd #{latest_release}; rvm use 1.9.2##{application} --rvmrc --create && rvm rvmrc trust"
end
end
end

Resources