Dan Sharp
Dan Sharp

Reputation: 1279

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,

Upvotes: 10

Views: 3786

Answers (3)

B Seven
B Seven

Reputation: 45943

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.

Upvotes: 0

averell
averell

Reputation: 3772

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.

Upvotes: 0

max
max

Reputation: 101811

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

Upvotes: 3

Related Questions