When should I set up application constants?
When is it safe in the initialisation process to use the Rails libraries?
Where should I add code to perform application initialisation operations?
Though most people understand that your environment files are the key to answering some of these problems, how to actually solve them is not well known.
I’ll attempt to clarify what to use and when to use it. Out of this discussion we can hopefully add the relevant documentation to the Rails core for 1.2 onwards.
Keep in mind that i’m only describing the default versions of the Rails generated environment.rb and boot.rb. You could, if you wanted, customise these however you like.
First step in loading your Rails application
The first step to your Rails application being loaded is the “requiring” of your environment.rb file. In fact, this is the first of 3 lines that makes up the FCGI dispatcher, dispatch.fcgi:
require File.dirname(__FILE__) + "/../config/environment"
require 'fcgi_handler'
RailsFCGIHandler.process!
It’s within your environment.rb that the entire Rails environment and application environment is set up, ready to start taking requests.
Your default environment.rb looks something like this:
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
# config
end
boot.rb
The first thing your environment.rb does is load boot.rb, which does two things:
- Set the
RAILS_ROOTconstant - Adds the Rails libraries and your application’s code to the
LOAD_PATH
That’s it for boot.rb.
Rails::Initializer.run and per-environment configs
The second thing your environment.rb does is execute Rails::Initializer.run.
After "require"ing the Rails framework, your environment’s specific config file is loaded. In development, this would be config/environments/development.rb.
Though the Rails framework has been “required”, you can not consider the Rails framework or your application as being loaded when you are in the enviroment’s config file (I found this out the hard way). This means you can’t use ActiveRecord and you can’t reference plugins.
So where does that leave us?
One option would be to move environment-specific initialisation into the environment.rb file, below the Rails::Initializer.run block:
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
# config
end
# Set up app-wide configs
if RAILS_ENV == "production"
# Set up some caches
end
if RAILS_ENV == "development"
# Set up some development mocks
end
if RAILS_ENV == "test"
# Set up some testing mocks
end
Yuck! Now we’ve scattered each environment’s configuration all over the shop.
How can we keep each environment’s code neatly tucked away in config/environments/, whilst keeping in mind the Rails framework hasn’t yet loaded in the environment’s config file?
The answer: Configuration#after_initialize.
config.after_initialize
From the rdocs:
Sets a block which will be executed after rails has been fully initialized. Useful for per-environment configuration which depends on the framework being fully initialized.
For example, you might need to replace/mock a method in a class that depends on the Rails framework, or set an environment-specific plugin configuration. This is what you’d do in after_initialize.
I’ve moved putting all app-specific calls in my environment files into after_initialize blocks for consistency.
config.to_prepare
The Dispatcher#to_prepare method is similar to Configuration#after_initialize, but is used to execute code before each request, rather than on application initialization.
If you have classes that are being reloaded on each request during development, and want to set certain class attributes or other settings after they are reloading, you’ll want to specify them in to_prepare rather than after_initialize.
What might look like this in your config/environments/production.rb:
config.after_initialize do
SystemPaths.system_config_file = "#{RAILS_ROOT}/configs/system.yml"
end
might look like this in config/environments/development.rb:
config.to_prepare do
SystemPaths.system_config_file = "#{RAILS_ROOT}/configs/system.yml"
end
Environment vs Model
If you’ve hit a wall trying to do something in your environment, maybe the behaviour should really belong in your model? Environment’s shouldn’t really execute a whole bunch of code, they’re really just meant to set up your application so it can be invoked (via the console, via script/runner, via the dispatcher or otherwise).
See my previous article avoid DB calls when setting up your environment for a more concrete example of trying to do too much in your environment initialisation.
So where are all the hooks?
All the places you have a chance to initialise code when setting up your environment, in order of execution:

- config/environment.rb: before the initializer block
- config/environment.rb: inside the initializer block
- config/environments/#{RAILS_ENV}.rb: top level
- config/environments/#{RAILS_ENV}.rb_: afterinitialize
- environment.rb: after the initializer block
and also the less used, but still notable, config.to_prepare, which gets executed by the Dispatcher on a per-request basis.
Which one to use?
Naturally, the next question will be “I have situation X. Where should I do my configuration?” Unfortunately there’s no easy answer, and all I can say is “it depends.”
If the initialisation code does not depend on the Rails framework or any plugins, it can be placed anywhere.
If the initialisation code does depend on Rails or any plugins being available, it can be placed in either an after_initialize block or at the bottom of environment.rb.
I hope this article clarifies things somewhat. If we can digest this kind of information into the Rails documentation (preferably as a patch to the docs and generated config files) then hopefully people won’t be confused by this simple yet somewhat scary config initialisation process.
Archived comments
Comments were previously allowed on articles. Though no new comments are being accepted you can see the old comments below.
-
Nice article, Tim. There’s all kinds of nuggests in Rails which you really have to dig for, but most of them are worth the effort.
-
Tim, I came across a need for this just the other day. Had a plugin that added functionality to acts_as_tree but Rails insisted that acts_as_tree wasn’t part of ActiveRecord::Base, this explains why.
-
Hey, Nice article! Needed to know how to find RAILS_ROOT but hey it’s already there :)
-
Very helpful, Tim. I’ve been struggling with initialization issues and this was exactly the information I needed.
-
Good find, Tim. I’ve been frustrated with the environment-specific configs until today. #after_initialize will be very handy (and it’ll keep my environment.rb free from clutter). Thanks for posting this article!
-
Thanks for this very useful post!
-
How would one “initialize a model” on application startup?
I have a error that comes up only upon the FIRST request made to a particular model. Any request thereafter works…. This leads me to think that the model is not loaded in memory — or initialized — until after the first request. Any ideas????
mcphersonz AT gmail DOT com
-
Great article. It’s exactly what I was looking for… thank you for this writing !
-
i am a soft developer in china, thanks for your post.