2012-09-01 17:25:58 -04:00
The Rails Initialization Process
================================
2010-03-27 21:02:59 -04:00
2012-05-22 11:32:12 -04:00
This guide explains the internals of the initialization process in Rails
as of Rails 4. It is an extremely in-depth guide and recommended for advanced Rails developers.
2010-03-27 21:02:59 -04:00
2012-11-29 17:25:02 -05:00
After reading this guide, you will know:
2012-12-07 12:50:09 -05:00
* How to use `rails server` .
2013-06-28 03:41:30 -04:00
* The timeline of Rails' initialization sequence.
* Where different files are required by the boot sequence.
* How the Rails::Server interface is defined and used.
2010-03-27 21:02:59 -04:00
2012-09-01 17:25:58 -04:00
--------------------------------------------------------------------------------
2010-03-27 21:02:59 -04:00
2012-06-10 20:55:12 -04:00
This guide goes through every method call that is
2012-06-17 14:11:22 -04:00
required to boot up the Ruby on Rails stack for a default Rails 4
application, explaining each part in detail along the way. For this
2013-06-28 03:41:30 -04:00
guide, we will be focusing on what happens when you execute `rails server`
to boot your app.
2010-12-14 23:08:08 -05:00
NOTE: Paths in this guide are relative to Rails or a Rails application unless otherwise specified.
2010-03-27 21:02:59 -04:00
2012-09-03 21:21:24 -04:00
TIP: If you want to follow along while browsing the Rails [source
code](https://github.com/rails/rails), we recommend that you use the `t`
2012-08-11 02:19:51 -04:00
key binding to open the file finder inside GitHub and find files
2012-06-17 14:14:19 -04:00
quickly.
2012-09-01 17:25:58 -04:00
Launch!
-------
2010-03-27 21:02:59 -04:00
2013-11-06 07:54:22 -05:00
Let's start to boot and initialize the app. A Rails application is usually
started by running `rails console` or `rails server` .
### `railties/bin/rails`
The `rails` in the command `rails server` is a ruby executable in your load
path. This executable contains the following lines:
```ruby
version = ">= 0"
load Gem.bin_path('railties', 'rails', version)
```
If you try out this command in a Rails console, you would see that this loads
`railties/bin/rails` . A part of the file `railties/bin/rails.rb` has the
following code:
```ruby
require "rails/cli"
```
The file `railties/lib/rails/cli` in turn calls
`Rails::AppRailsLoader.exec_app_rails` .
### `railties/lib/rails/app_rails_loader.rb`
The primary goal of the function `exec_app_rails` is to execute your app's
`bin/rails` . If the current directory does not have a `bin/rails` , it will
navigate upwards until it finds a `bin/rails` executable. Thus one can invoke a
`rails` command from anywhere inside a rails application.
For `rails server` the equivalent of the following command is executed:
```bash
$ exec ruby bin/rails server
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
### `bin/rails`
2010-12-14 23:08:08 -05:00
2011-11-19 21:36:50 -05:00
This file is as follows:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2013-01-06 18:13:47 -05:00
#!/usr/bin/env ruby
2013-05-28 08:36:18 -04:00
APP_PATH = File.expand_path('../../config/application', __FILE__ )
2013-08-12 04:15:20 -04:00
require_relative '../config/boot'
2011-06-04 15:28:21 -04:00
require 'rails/commands'
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
The `APP_PATH` constant will be used later in `rails/commands` . The `config/boot` file referenced here is the `config/boot.rb` file in our application which is responsible for loading Bundler and setting it up.
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `config/boot.rb`
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
`config/boot.rb` contains:
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
# Set up gems listed in the Gemfile.
2012-05-22 11:48:46 -04:00
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__ )
2013-11-01 13:07:27 -04:00
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
In a standard Rails application, there's a `Gemfile` which declares all
dependencies of the application. `config/boot.rb` sets
`ENV['BUNDLE_GEMFILE']` to the location of this file. If the Gemfile
2013-06-28 03:41:30 -04:00
exists, then `bundler/setup` is required. The require is used by Bundler to
configure the load path for your Gemfile's dependencies.
2012-05-22 11:48:46 -04:00
2013-04-18 22:00:47 -04:00
A standard Rails application depends on several gems, specifically:
* abstract
* actionmailer
* actionpack
* activemodel
* activerecord
* activesupport
* arel
* builder
* bundler
* erubis
* i18n
* mail
* mime-types
* polyglot
* rack
* rack-cache
* rack-mount
* rack-test
* rails
* railties
* rake
* sqlite3-ruby
* thor
* treetop
* tzinfo
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `rails/commands.rb`
2010-12-14 23:08:08 -05:00
2013-11-08 04:43:59 -05:00
Once `config/boot.rb` has finished, the next file that is required is
`rails/commands` , which helps in expanding aliases. In the current case, the
2013-11-24 13:55:46 -05:00
`ARGV` array simply contains `server` which will be passed over:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2012-05-22 11:55:59 -04:00
ARGV < < '--help' if ARGV.empty?
2011-06-04 15:28:21 -04:00
aliases = {
"g" => "generate",
2012-05-26 16:09:54 -04:00
"d" => "destroy",
2011-06-04 15:28:21 -04:00
"c" => "console",
"s" => "server",
2011-08-14 10:45:22 -04:00
"db" => "dbconsole",
"r" => "runner"
2011-06-04 15:28:21 -04:00
}
2010-12-14 23:08:08 -05:00
2011-06-04 15:28:21 -04:00
command = ARGV.shift
command = aliases[command] || command
2013-11-08 04:37:38 -05:00
require 'rails/commands/commands_tasks'
Rails::CommandsTasks.new(ARGV).run_command!(command)
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-05-22 11:55:59 -04:00
TIP: As you can see, an empty ARGV list will make Rails show the help
snippet.
2013-11-08 04:43:59 -05:00
If we had used `s` rather than `server` , Rails would have used the `aliases`
defined here to find the matching command.
2013-11-08 04:37:38 -05:00
2013-11-08 04:43:59 -05:00
### `rails/commands/command_tasks.rb`
When one types an incorrect rails command, the `run_command` is responsible for
2013-11-24 13:55:46 -05:00
throwing an error message. If the command is valid, a method of the same name
2013-11-08 04:43:59 -05:00
is called.
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2013-11-08 04:43:59 -05:00
COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help)
def run_command!(command)
if COMMAND_WHITELIST.include?(command)
send(command)
else
write_error_message(command)
end
end
```
With the `server` command, Rails will further run the following code:
```ruby
def set_application_directory!
Dir.chdir(File.expand_path('../../', APP_PATH)) unless
File.exist?(File.expand_path("config.ru"))
end
def server
set_application_directory!
require_command!("server")
2011-06-04 15:28:21 -04:00
2013-01-05 17:57:03 -05:00
Rails::Server.new.tap do |server|
2011-06-04 15:28:21 -04:00
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
2013-01-05 17:57:03 -05:00
end
2013-11-08 04:43:59 -05:00
end
def require_command!(command)
require "rails/commands/#{command}"
end
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2013-11-08 04:43:59 -05:00
This file will change into the Rails root directory (a path two directories up
from `APP_PATH` which points at `config/application.rb` ), but only if the
`config.ru` file isn't found. This then requires `rails/commands/server` which
sets up the `Rails::Server` class.
2012-06-09 15:20:47 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2012-06-09 15:20:47 -04:00
require 'fileutils'
require 'optparse'
require 'action_dispatch'
module Rails
class Server < ::Rack::Server
2012-09-01 17:08:06 -04:00
```
2012-06-09 15:20:47 -04:00
2012-09-01 21:37:59 -04:00
`fileutils` and `optparse` are standard Ruby libraries which provide helper functions for working with files and parsing options.
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `actionpack/lib/action_dispatch.rb`
2010-12-14 23:08:08 -05:00
2012-06-17 14:30:20 -04:00
Action Dispatch is the routing component of the Rails framework.
2013-04-18 22:09:10 -04:00
It adds functionality like routing, session, and common middlewares.
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `rails/commands/server.rb`
2010-12-14 23:08:08 -05:00
2013-04-18 22:09:10 -04:00
The `Rails::Server` class is defined in this file by inheriting from `Rack::Server` . When `Rails::Server.new` is called, this calls the `initialize` method in `rails/commands/server.rb` :
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def initialize(*)
super
set_environment
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
Firstly, `super` is called which calls the `initialize` method on `Rack::Server` .
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
### Rack: `lib/rack/server.rb`
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
`Rack::Server` is responsible for providing a common server interface for all Rack-based applications, which Rails is now a part of.
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
The `initialize` method in `Rack::Server` simply sets a couple of variables:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def initialize(options = nil)
@options = options
@app = options[:app] if options && options[:app]
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
In this case, `options` will be `nil` so nothing happens in this method.
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
After `super` has finished in `Rack::Server` , we jump back to `rails/commands/server.rb` . At this point, `set_environment` is called within the context of the `Rails::Server` object and this method doesn't appear to do much at first glance:
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def set_environment
ENV["RAILS_ENV"] ||= options[:environment]
end
2012-09-01 17:08:06 -04:00
```
2010-03-31 05:50:13 -04:00
2012-09-01 21:37:59 -04:00
In fact, the `options` method here does quite a lot. This method is defined in `Rack::Server` like this:
2010-03-31 05:50:13 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def options
@options ||= parse_options(ARGV)
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
Then `parse_options` is defined like this:
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def parse_options(args)
options = default_options
2010-03-31 05:50:13 -04:00
2011-06-04 15:28:21 -04:00
# Don't evaluate CGI ISINDEX parameters.
# http://hoohoo.ncsa.uiuc.edu/cgi/cl.html
args.clear if ENV.include?("REQUEST_METHOD")
2010-03-27 21:02:59 -04:00
2011-06-04 15:28:21 -04:00
options.merge! opt_parser.parse! args
options[:config] = ::File.expand_path(options[:config])
ENV["RACK_ENV"] = options[:environment]
options
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
With the `default_options` set to this:
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def default_options
{
2013-09-06 14:41:04 -04:00
environment: ENV['RACK_ENV'] || "development",
pid: nil,
Port: 9292,
Host: "0.0.0.0",
AccessLog: [],
config: "config.ru"
2011-06-04 15:28:21 -04:00
}
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
There is no `REQUEST_METHOD` key in `ENV` so we can skip over that line. The next line merges in the options from `opt_parser` which is defined plainly in `Rack::Server`
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def opt_parser
Options.new
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-06 22:26:59 -04:00
The class **is** defined in `Rack::Server` , but is overwritten in `Rails::Server` to take different arguments. Its `parse!` method begins like this:
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def parse!(args)
args, options = args.dup, {}
2010-12-14 23:08:08 -05:00
2011-08-05 15:31:54 -04:00
opt_parser = OptionParser.new do |opts|
opts.banner = "Usage: rails server [mongrel, thin, etc] [options]"
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v }
2010-03-31 05:50:13 -04:00
...
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
This method will set up keys for the `options` which Rails will then be
able to use to determine how its server should run. After `initialize`
has finished, we jump back into `rails/server` where `APP_PATH` (which was
2012-06-10 21:20:40 -04:00
set earlier) is required.
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `config/application`
2012-06-10 21:26:54 -04:00
2013-06-28 03:41:30 -04:00
When `require APP_PATH` is executed, `config/application.rb` is loaded (recall
that `APP_PATH` is defined in `bin/rails` ). This file exists in your application
and it's free for you to change based on your needs.
2012-06-10 21:26:54 -04:00
2012-09-01 21:37:59 -04:00
### `Rails::Server#start`
2010-12-14 23:08:08 -05:00
2013-11-12 08:44:10 -05:00
After `config/application` is loaded, `server.start` is called. This method is
defined like this:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def start
2013-11-12 08:44:10 -05:00
print_boot_information
2011-06-04 15:28:21 -04:00
trap(:INT) { exit }
2013-11-12 08:44:10 -05:00
create_tmp_directories
log_to_stdout if options[:log_stdout]
2011-06-04 15:28:21 -04:00
2013-11-12 08:44:10 -05:00
super
...
end
private
def print_boot_information
...
puts "=> Run `rails server -h` for more startup options"
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
2010-03-31 05:50:13 -04:00
end
2011-06-04 15:28:21 -04:00
2013-11-12 08:44:10 -05:00
def create_tmp_directories
%w(cache pids sessions sockets).each do |dir_to_make|
FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make))
end
end
def log_to_stdout
2012-05-23 11:45:48 -04:00
wrapped_app # touch the app so the logger is set up
console = ActiveSupport::Logger.new($stdout)
console.formatter = Rails.logger.formatter
2013-11-12 08:44:10 -05:00
console.level = Rails.logger.level
2012-05-23 11:45:48 -04:00
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-05-23 11:45:48 -04:00
This is where the first output of the Rails initialization happens. This
2012-09-01 21:37:59 -04:00
method creates a trap for `INT` signals, so if you `CTRL-C` the server,
2012-05-23 11:45:48 -04:00
it will exit the process. As we can see from the code here, it will
2012-09-01 21:37:59 -04:00
create the `tmp/cache` , `tmp/pids` , `tmp/sessions` and `tmp/sockets`
directories. It then calls `wrapped_app` which is responsible for
2012-06-10 21:45:03 -04:00
creating the Rack app, before creating and assigning an
2012-09-01 21:37:59 -04:00
instance of `ActiveSupport::Logger` .
2012-05-23 11:45:48 -04:00
2012-09-01 21:37:59 -04:00
The `super` method will call `Rack::Server.start` which begins its definition like this:
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2012-05-23 11:53:08 -04:00
def start & blk
2011-06-04 15:28:21 -04:00
if options[:warn]
$-w = true
end
2010-12-14 23:08:08 -05:00
2011-06-04 15:28:21 -04:00
if includes = options[:include]
$LOAD_PATH.unshift(*includes)
end
2010-12-14 23:08:08 -05:00
2011-06-04 15:28:21 -04:00
if library = options[:require]
require library
end
2010-12-14 23:08:08 -05:00
2011-06-04 15:28:21 -04:00
if options[:debug]
$DEBUG = true
require 'pp'
p options[:server]
pp wrapped_app
pp app
end
2010-03-27 21:02:59 -04:00
2012-05-23 11:53:08 -04:00
check_pid! if options[:pid]
2010-03-27 21:02:59 -04:00
2012-05-23 11:53:08 -04:00
# Touch the wrapped app, so that the config.ru is loaded before
# daemonization (i.e. before chdir, etc).
wrapped_app
daemonize_app if options[:daemonize]
write_pid if options[:pid]
trap(:INT) do
if server.respond_to?(:shutdown)
server.shutdown
else
exit
end
end
server.run wrapped_app, options, & blk
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
The interesting part for a Rails app is the last line, `server.run` . Here we encounter the `wrapped_app` method again, which this time
2012-06-10 21:45:03 -04:00
we're going to explore more (even though it was executed before, and
2013-07-14 06:01:46 -04:00
thus memoized by now).
2010-03-27 21:02:59 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
@wrapped_app ||= build_app app
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
The `app` method here is defined like so:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
def app
@app ||= begin
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
2010-03-27 21:02:59 -04:00
end
2011-06-04 15:28:21 -04:00
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
self.options.merge! options
app
2010-12-14 23:08:08 -05:00
end
2011-06-04 15:28:21 -04:00
end
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
The `options[:config]` value defaults to `config.ru` which contains this:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
# This file is used by Rack-based servers to start the application.
2010-12-14 23:08:08 -05:00
2013-05-28 08:36:18 -04:00
require ::File.expand_path('../config/environment', __FILE__ )
2012-05-23 12:01:21 -04:00
run < %= app_const %>
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
The `Rack::Builder.parse_file` method here takes the content from this `config.ru` file and parses it using this code:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2012-09-03 21:21:24 -04:00
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
2010-12-14 23:08:08 -05:00
TOPLEVEL_BINDING, config
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder` . This is where the majority of the initialization process of Rails happens. The `require` line for `config/environment.rb` in `config.ru` is the first to run:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2013-05-28 08:36:18 -04:00
require ::File.expand_path('../config/environment', __FILE__ )
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `config/environment.rb`
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
This file is the common file required by `config.ru` (`rails server`) and Passenger. This is where these two ways to run the server meet; everything before this point has been Rack and Rails setup.
2010-03-27 21:02:59 -04:00
2012-09-01 21:37:59 -04:00
This file begins with requiring `config/application.rb` .
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `config/application.rb`
2010-12-14 23:08:08 -05:00
2012-09-06 22:26:59 -04:00
This file requires `config/boot.rb` , but only if it hasn't been required before, which would be the case in `rails server` but **wouldn't** be the case with Passenger.
2010-12-14 23:08:08 -05:00
2011-04-13 20:49:14 -04:00
Then the fun begins!
2010-12-22 23:35:59 -05:00
2012-09-01 17:25:58 -04:00
Loading Rails
-------------
2010-12-22 23:35:59 -05:00
2012-09-01 21:37:59 -04:00
The next line in `config/application.rb` is:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
require 'rails/all'
2012-09-01 17:08:06 -04:00
```
2010-12-14 23:08:08 -05:00
2012-09-01 21:37:59 -04:00
### `railties/lib/rails/all.rb`
2010-12-14 23:08:08 -05:00
2012-06-17 14:30:20 -04:00
This file is responsible for requiring all the individual frameworks of Rails:
2010-12-14 23:08:08 -05:00
2012-09-01 17:08:06 -04:00
```ruby
2011-06-04 15:28:21 -04:00
require "rails"
2010-12-14 23:08:08 -05:00
2011-06-04 15:28:21 -04:00
%w(
2010-12-14 23:08:08 -05:00
active_record
action_controller
action_mailer
rails/test_unit
2012-10-18 00:03:24 -04:00
sprockets
2011-06-04 15:28:21 -04:00
).each do |framework|
begin
require "#{framework}/railtie"
rescue LoadError
2010-03-27 21:02:59 -04:00
end
2011-06-04 15:28:21 -04:00
end
2012-09-01 17:08:06 -04:00
```
2010-03-27 21:02:59 -04:00
2012-06-10 21:45:03 -04:00
This is where all the Rails frameworks are loaded and thus made
2012-08-11 02:19:51 -04:00
available to the application. We won't go into detail of what happens
2012-06-10 21:45:03 -04:00
inside each of those frameworks, but you're encouraged to try and
explore them on your own.
2010-12-14 23:08:08 -05:00
2012-06-10 21:45:03 -04:00
For now, just keep in mind that common functionality like Rails engines,
2013-04-18 22:09:10 -04:00
I18n and Rails configuration are all being defined here.
2012-06-13 11:34:48 -04:00
2012-09-01 21:37:59 -04:00
### Back to `config/environment.rb`
2012-06-13 11:34:48 -04:00
2013-06-28 03:41:30 -04:00
The rest of `config/application.rb` defines the configuration for the
`Rails::Application` which will be used once the application is fully
initialized. When `config/application.rb` has finished loading Rails and defined
2013-04-18 22:09:10 -04:00
the application namespace, we go back to `config/environment.rb` ,
where the application is initialized. For example, if the application was called
`Blog` , here we would find `Blog::Application.initialize!` , which is
2012-09-01 21:37:59 -04:00
defined in `rails/application.rb`
2012-06-13 11:48:45 -04:00
2012-09-01 21:37:59 -04:00
### `railties/lib/rails/application.rb`
2012-06-13 11:48:45 -04:00
2012-09-01 21:37:59 -04:00
The `initialize!` method looks like this:
2012-06-13 11:48:45 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2012-06-13 11:48:45 -04:00
def initialize!(group=:default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
2012-09-01 17:08:06 -04:00
```
2012-06-13 11:48:45 -04:00
2013-10-09 16:16:12 -04:00
As you can see, you can only initialize an app once. The initializers are run through
the `run_initializers` method which is defined in `railties/lib/rails/initializable.rb`
2012-06-13 11:48:45 -04:00
2013-10-09 16:16:12 -04:00
```ruby
def run_initializers(group=:default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort_each do |initializer|
initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
```
2012-06-13 11:48:45 -04:00
2013-10-09 16:16:12 -04:00
The run_initializers code itself is tricky. What Rails is doing here is
traversing all the class ancestors looking for those that respond to an
`initializers` method. It then sorts the ancestors by name, and runs them.
For example, the `Engine` class will make all the engines available by
providing an `initializers` method on them.
2012-06-13 11:48:45 -04:00
2013-06-28 03:41:30 -04:00
The `Rails::Application` class, as defined in `railties/lib/rails/application.rb`
defines `bootstrap` , `railtie` , and `finisher` initializers. The `bootstrap` initializers
prepare the application (like initializing the logger) while the `finisher`
initializers (like building the middleware stack) are run last. The `railtie`
initializers are the initializers which have been defined on the `Rails::Application`
itself and are run between the `bootstrap` and `finishers` .
2012-09-01 21:37:59 -04:00
After this is done we go back to `Rack::Server`
2012-06-13 11:48:45 -04:00
2012-09-01 17:25:58 -04:00
### Rack: lib/rack/server.rb
2012-06-13 11:59:14 -04:00
2012-09-01 21:37:59 -04:00
Last time we left when the `app` method was being defined:
2012-06-13 11:59:14 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2012-06-13 11:59:14 -04:00
def app
@app ||= begin
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
self.options.merge! options
app
end
end
2012-09-01 17:08:06 -04:00
```
2012-06-13 11:59:14 -04:00
2012-09-01 21:37:59 -04:00
At this point `app` is the Rails app itself (a middleware), and what
2012-06-13 11:59:14 -04:00
happens next is Rack will call all the provided middlewares:
2012-09-01 17:08:06 -04:00
```ruby
2012-06-13 11:59:14 -04:00
def build_app(app)
middleware[options[:environment]].reverse_each do |middleware|
middleware = middleware.call(self) if middleware.respond_to?(:call)
next unless middleware
klass = middleware.shift
app = klass.new(app, *middleware)
end
app
end
2012-09-01 17:08:06 -04:00
```
2012-06-13 11:59:14 -04:00
2012-09-01 21:37:59 -04:00
Remember, `build_app` was called (by wrapped_app) in the last line of `Server#start` .
2012-06-13 11:59:14 -04:00
Here's how it looked like when we left:
2012-09-01 17:08:06 -04:00
```ruby
2012-06-13 11:59:14 -04:00
server.run wrapped_app, options, & blk
2012-09-01 17:08:06 -04:00
```
2012-06-13 11:59:14 -04:00
2012-09-01 21:37:59 -04:00
At this point, the implementation of `server.run` will depend on the
2012-06-14 12:05:10 -04:00
server you're using. For example, if you were using Mongrel, here's what
2012-09-01 21:37:59 -04:00
the `run` method would look like:
2012-06-14 12:05:10 -04:00
2012-09-01 17:08:06 -04:00
```ruby
2012-06-14 12:05:10 -04:00
def self.run(app, options={})
server = ::Mongrel::HttpServer.new(
options[:Host] || '0.0.0.0',
options[:Port] || 8080,
options[:num_processors] || 950,
options[:throttle] || 0,
options[:timeout] || 60)
# Acts like Rack::URLMap, utilizing Mongrel's own path finding methods.
# Use is similar to #run , replacing the app argument with a hash of
# { path=>app, ... } or an instance of Rack::URLMap.
if options[:map]
if app.is_a? Hash
app.each do |path, appl|
path = '/'+path unless path[0] == ?/
server.register(path, Rack::Handler::Mongrel.new(appl))
end
elsif app.is_a? URLMap
app.instance_variable_get(:@mapping).each do |(host, path, appl)|
next if !host.nil? & & !options[:Host].nil? & & options[:Host] != host
path = '/'+path unless path[0] == ?/
server.register(path, Rack::Handler::Mongrel.new(appl))
end
else
raise ArgumentError, "first argument should be a Hash or URLMap"
end
else
server.register('/', Rack::Handler::Mongrel.new(app))
end
2013-05-28 08:36:18 -04:00
yield server if block_given?
2012-06-14 12:05:10 -04:00
server.run.join
end
2012-09-01 17:08:06 -04:00
```
2012-06-14 12:05:10 -04:00
2012-08-11 02:19:51 -04:00
We won't dig into the server configuration itself, but this is
2012-06-14 12:05:10 -04:00
the last piece of our journey in the Rails initialization process.
2012-08-11 02:19:51 -04:00
This high level overview will help you understand when your code is
2012-06-14 12:05:10 -04:00
executed and how, and overall become a better Rails developer. If you
still want to know more, the Rails source code itself is probably the
best place to go next.