#72 Adding an Environment (revised)
This episode covers creating custom environments. It’s a simple topic but one that some Rails developers may not be aware of. When we generate a new Rails application we get three environments by default:
production. There’s nothing special about these particular environments, though, and there are very few places in the Rails source code that refer to them. What makes them unique is the way they’re configured in an application’s config files.
For example the default
production.rb config file has
config.cache_classes set to
true which means that the app’s classes won’t be reloaded between requests for performance reasons. In development mode it’s more convenient for these classes to be reloaded automatically and so in the equivalent
development.rb file this option is set to
false instead. To get more of an idea of the differences between the environments you can read through the
test.rb files in an app’s
/config/environments directory and compare them.
Adding a Custom Environment
As there’s nothing special about any given environment we can create as many custom environments as we want. We could, for example, add a staging environment to an application which behaves like production but which has a few development goodies thrown in. All we need to do is add a config file for that environment. As we want this environment to behave like production we’ll copy that environment’s configuration into our new staging environment, but we’ll change a couple of things such as setting the
When we add a new environment we should also take a look at the application’s other configuration files as some of them, such as the
database.yml file, contain code specific to each environment. We’ll need to add another entry here for our staging environment.
staging: adapter: sqlite3 database: db/staging.sqlite3 pool: 5 timeout: 5000
We could reuse the development database in the staging environment, but giving it a separate database means that we could, for example, add a lot of data to so that we can stress-test that app in staging.
We can now start up our application in our new environment by using the
$ rails s -e staging => Booting WEBrick => Rails 3.1.3 application starting in staging on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2012-01-24 19:58:52] INFO WEBrick 1.3.1 [2012-01-24 19:58:52] INFO ruby 1.9.2 (2011-07-09) [x86_64-darwin11.2.0] [2012-01-24 19:58:52] INFO WEBrick::HTTPServer#start: pid=13416 port=3000
If we want to start up the console in our new environment we just pass its name in as an argument.
$ rails c staging Loading staging environment (Rails 3.1.3) 1.9.2p290 :001 >
Alternatively we can set the
RAILS_ENV environment variable and then run a command.
$ RAILS_ENV=staging rails s
If we want to change the default Rails environment we can export this setting. Any future commands will automatically then be run in the specified environment while we have the same terminal session running.
$ export RAILS_ENV=staging
If we have a dedicated staging server we can put this command in our
zshrc file and make that environment a permanent default.
Next we’ll look at Bundler. As you’re probably aware we can use the group option to restrict a gem to a specific environment, like this:
source 'http://rubygems.org' gem 'rails', '3.1.3' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' gem 'sqlite3' # Gems used only for assets and not required # in production environments by default. group :assets do gem 'sass-rails', '~> 3.1.4' gem 'coffee-rails', '~> 3.1.1' gem 'uglifier', '>= 1.0.3' end gem 'jquery-rails' gem 'tire' group :staging do gem 'ruby-prof' end
ruby-prof gem will now only be required in the staging environment.
The groups don’t always have to match a given environment, however. For example in a Rails 3.1 gemfile there’s an
assets group that doesn’t match any environment. If we call our
staging group something else, say
profiling, its gems won’t be loaded at all by default. We can change this by modifying the
application.rb config file. At the top of this file is a
Rails.groups method which is used to assign groups to a a set of environments. We’ll set the
profiling group so that it’s loaded in the staging and development environments.
if defined?(Bundler) # If you precompile assets before deploying to production, use this line Bundler.require(*Rails.groups(:assets => %w(development test), :profiling => %w[staging development])) # If you want your assets lazily compiled in production, use this line # Bundler.require(:default, :assets, Rails.env) end
The advantage of this approach is that we can add more complex logic here if we want to customize when this group is loaded at runtime instead of specifying which environment it should be loaded in in the gemfile.