Environment variables locally and Heroku

14,490

Solution 1

Update:

I now use the dotenv gem instead of the example below. So instead of ignoring the env.rb file, I now ignore the .env file with Git.

Original post:

Try this,

# /env.rb

ENV['aws_bucket'] = 'my_bucket'
ENV['aws_access_key'] = 'my_access_key'
ENV['aws_access_secret'] = 'my_access_secret'

This file sets the same ENV values as heroku config would do.

# /config.rb

require './env' if File.exists?('env.rb')

The env.rb will only get required if it exists.

# /.gitignore

/env.rb

The env.rb has been added to the .gitignore file so it isn't kept in Git.

You would then access the values using ENV['key'] instead of config['key'].

You might need to change the path to the env.rb if it's not in the same directory as the config.rb file.

EDIT:

From looking at your Rakefile in the previous question, you need to change it to this:

# Rakefile

require 'bundler/setup'
Bundler.require(:default)
require './env' if File.exists?('env.rb')

AssetSync.configure do |con|
 con.fog_provider = 'AWS'
 con.fog_region = 'eu-west-1'
 con.fog_directory = ENV['aws_bucket']
 con.aws_access_key_id = ENV['aws_access_key']
 con.aws_secret_access_key = ENV['aws_access_secret']
 con.prefix = "assets"
 con.public_path = Pathname("./public")
end

namespace :assets do
  desc "Precompile assets"
  task :precompile do
    AssetSync.sync
  end
end

I've assumed that the only method in /config/config.rb was the config method so I've removed the,

require './config/config.rb'
include MyConfig

And swapped the config[key] for the ENV[key] values defined in env.rb. You may need to change the key names to match up.

Solution 2

I do something similar to Sam's suggestion, but a little bit different. I have a YAML config file too, but I wrap the reading of it in a Rake task, which then runs the app.

# in the Rakefile

require 'yaml'

def set_connstring
  s = %Q!postgres://#{ENV["DB_APP"]}@localhost/#{ENV["DB_APP"]}!
  ENV['DATABASE_URL'] ||= ENV["RACK_ENV"] == "test" ? "#{s}.test" : s
end


def basic_environment
  warn "  Setting up environment..."

  file = File.expand_path( File.join File.dirname(__FILE__), "./config.yml" )
  if File.exist? file
    YAML.load_file(file).each do |k,v|
      warn "-> #{k}"
      ENV[k.upcase] = v
    end
  end

  set_connstring()
end

namespace :app do

  desc "Set up the environment locally"
  task :environment do
    basic_environment()
  end

  desc "Run the app locally"
  task :run_local => "app:environment" do
    exec "bin/rackup config.ru -p #{ENV['RUN_LOCAL_PORT']}"
  end
end

It means I can run it locally without any code inside the app to deal with this.


Edit: a quick aside, I notice you have Bundler.require(:default) in your Rakefile. If you use bundle install --binstubs then Bundler installs all executables into a dir named "bin/" within the project. Then, if you run any of those executables they automatically use the libraries installed by Bundler, no need to require via Bundler. See http://gembundler.com/v1.2/man/bundle-exec.1.html.

Solution 3

You could delete the yaml, and describe the environment variables in a .env file then start your app with foreman start. See https://devcenter.heroku.com/articles/config-vars#local-setup


Or keep your hybrid system, where you load a yaml in dev, and use environment variables on heroku.

Share:
14,490

Related videos on Youtube

Richlewis
Author by

Richlewis

Software Tester Ruby Ruby On Rails HTML CSS Javascript jQuery Follow me on twitter @richl14

Updated on June 21, 2022

Comments

  • Richlewis
    Richlewis about 2 years

    I have a sinatra app in which i have a yml file to set environment variables, i call them using this method

    module MyConfig
    
     def config
      environment = ENV["RACK_ENV"] || "development"
      YAML.load_file("./config/config.yml")[environment]
     end
     end
    

    so when i want to use a variable i do this for example

    aws_access_key_id = config['aws_access_key']
    

    I have a .gitignore file that ignores config.yml when pushing to github for example.So when I push to heroku these environment variables will not be accessible?

    So this leaves me with using the heroku way of setting them like so

    heroku config:add aws_access_key= myapikey
    

    but heroku accesses these like

    aws_access_key_id = ENV['aws_access_key']
    

    How can i set my dev environment to use method config and heroku use ENV, am i looking at this the wrong way? or does my config method do this for me?

    Any help appreciated

    RAKEFILE

      require 'active_support/core_ext'
      require './config/config.rb'
      require 'bundler/setup'
      Bundler.require(:default)
    
       include MyConfig
    
      AssetSync.configure do |con|
      con.fog_provider = 'AWS'
      con.fog_region = 'eu-west-1'
      con.fog_directory = config['fog_directory']
      con.aws_access_key_id = config['aws_access_key']
      con.aws_secret_access_key = config['aws_secret_key']
      con.prefix = "assets"
      con.public_path = Pathname("./public")
      end
    
     namespace :assets do
     desc "Precompile assets"
     task :precompile do
      AssetSync.sync
     end
    end
    
  • Richlewis
    Richlewis over 11 years
    Thanks again for your help Sam, this time after running heroku run rake assets:precompile I get No such file or directory - /config/config.yml, which i understand as it is in the .gitignore file? any ideas how to get around this?
  • Sam
    Sam over 11 years
    Try removing YAML.load_file("./config/config.yml")[environment]. Since you have replaced the YAML file with the env.rb file, you no longer need to include it.
  • Richlewis
    Richlewis over 11 years
    yes i tried that but then i get undefined method or local variable config, as my rake file calls the method, ive posted the rakefile
  • Sam
    Sam over 11 years
    You will have to move all your YAML config[key] properties into env.rb and change them to ENV[key] properties. Then remove all references to the config[key] method in MyConfig.
  • Richlewis
    Richlewis over 11 years
    thanks very much, so if i wasnt going to use heroku i could stick with the config.yml way, but then again your method works just aswell even if i didnt use heroku
  • Sam
    Sam over 11 years
    Yes, I think the YAML way is cleaner if you can symlink on the server. Heroku uses ENV for it's config and doesn't allow symlinking, so the env.rb is more suitable here.
  • Richlewis
    Richlewis over 11 years
    almost there, error now warning: already initialized constant VALID_CHARACTER, after some reading i cant see anything wrong with my variables, im assuming there is no issue with ENV?
  • Sam
    Sam over 11 years
    Have you defined VALID_CHARACTER twice maybe? Possibly in different files? That error means the ruby constant named VALID_CHARACTER has been defined more than once. A ruby constant should only be defined once and shouldn't change.
  • Richlewis
    Richlewis over 11 years
    i cant even see it defined Once
  • Sam
    Sam over 11 years
    Try dropping the lines, require 'active_support/core_ext' and require 'asset_sync'. The Gemfile should be requiring these already. Answer updated.
  • Richlewis
    Richlewis over 11 years
    still get warning: already initialized constant VALID_CHARACTER, fog_directory cant be blank
  • Sam
    Sam over 11 years
    Does your ENV[] key in the rakefile match the key in the env.rb file for the bucket?
  • Richlewis
    Richlewis over 11 years
    ENV['aws_bucket'] = 'applecatering' (env) and con.fog_directory = ENV['aws_bucket'] (rakefile)
  • Richlewis
    Richlewis over 11 years
    i have my env.rb file in this structure config/env.rb so this is correct ye? require './env' if File.exists?('env.rb')
  • Sam
    Sam over 11 years
    Ah! Add require './config/env' if File.exists?('config/env.rb') to the Rakefile. It was removed when config.rb was removed.
  • Sam
    Sam over 11 years
    I'm out of ideas for now. Might have to come back to this later. VALID_CHARACTER is a contant in ActiveSupport and I think it's being defined twice but I'm not sure why.
  • Richlewis
    Richlewis over 11 years
    ok so in my gemfile i have gem 'activesupport', require: 'active_support', activesupport comes as default doesnt it?
  • Richlewis
    Richlewis over 11 years
    i have uninstalled gem activesupport and then re run bundle without this in the gemfile, still same problem
  • Sam
    Sam over 11 years
    I would suggest ignoring the warning message. AssetSync has activesupport in it's gemspec so that's getting included any way. It seems to be conflicting with the constant defined in the mail gem from the pony gemspec. If you remove the 'pony' gem, the warning will stop. Are there any other error messages after the pony gem is removed?
  • Richlewis
    Richlewis over 11 years
    thanks sam, but i need the pony gem for my mailer, ill try it just to see if message does infact go away but what then?
  • Richlewis
    Richlewis over 11 years
    rake command for heroku doesnt compile anything? just starts the rake and then goes back to terminal ready for new command
  • Richlewis
    Richlewis over 11 years
    actually just checked my aws account and last update was yesterday, not the rake task i just completed
  • Sylar
    Sylar over 5 years
    Thank you! In my case, Heroku uses the config.ru (.ru ext)