Esta guía pasa por todas las llamadas a métodos que se
necesario para iniciar la pila de Ruby on Rails para un Rails predeterminado
aplicación, explicando cada parte en detalle a lo largo del camino. Para esto
guía, nos centraremos en lo que sucede cuando ejecuta bin / rails server
para iniciar su aplicación.
Las rutas en esta guía son relativas a Rails o una aplicación Rails a menos que se especifique lo contrario.
SUGERENCIA: Si desea seguir la lectura mientras navega por Rails fuente
código, le recomendamos que utilice el t
enlace de teclas para abrir el buscador de archivos dentro de GitHub y buscar archivos
con rapidez.
1 Launch!
Comencemos a arrancar e inicializar la aplicación. Una aplicación Rails suele
comenzó ejecutando bin/rails console
o bin/rails server
.
1.1 bin/rails
Este archivo es el siguiente:
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative "../config/boot"
require "rails/commands"
La constante APP_PATH
se utilizará más adelante enrails / commands
. El archivo config / boot
al que se hace referencia aquí es el archivoconfig/boot.rb
en nuestra aplicación que es responsable de cargar Bundler y configurarlo.
1.2 config/boot.rb
config/boot.rb
contiene:
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require "bundler/setup" # Set up gems listed in the Gemfile.
En una aplicación estándar de Rails, hay un Gemfile
que declara todos
dependencias de la aplicación. Conjuntos de config/boot.rb
ENV['BUNDLE_GEMFILE']
a la ubicación de este archivo. Si el Gemfile
existe, entonces se requiere bundler/setup
. Bundler utiliza el require para
configure la ruta de carga para las dependencias de su Gemfile.
Una aplicación estándar de Rails depende de varias gemas, específicamente:
- actioncable
- actionmailer
- actionpack
- actionview
- activejob
- activemodel
- activerecord
- activestorage
- activesupport
- actionmailbox
- actiontext
- arel
- builder
- bundler
- erubi
- i18n
- mime-types
- rack
- rack-test
- rails
- railties
- rake
- sqlite3
- thor
- tzinfo
1.3 rails/commands.rb
Una vez que config/boot.rb
haya terminado, el siguiente archivo que se requiere es
rails/commands
, que ayuda a expandir los alias. En el caso actual, el
La matriz ARGV
simplemente contiene el server
que se pasará:
require "rails/command"
aliases = {
"g" => "generate",
"d" => "destroy",
"c" => "console",
"s" => "server",
"db" => "dbconsole",
"r" => "runner",
"t" => "test"
}
command = ARGV.shift
command = aliases[command] || command
Rails::Command.invoke command, ARGV
Si hubiéramos usado s
en lugar deservidor
, Rails habría usado los alias
definido aquí para encontrar el comando correspondiente.
1.4 rails/command.rb
Cuando uno escribe un comando Rails, invoke
intenta buscar un comando para el dado
espacio de nombres y ejecuta el comando si lo encuentra.
Si Rails no reconoce el comando, le entrega las riendas a Rake. para ejecutar una tarea con el mismo nombre.
Como se muestra, Rails::Command
muestra la salida de ayuda automáticamente si el namespace
esta vacio.
module Rails
module Command
class << self
def invoke(full_namespace, args = [], **config)
namespace = full_namespace = full_namespace.to_s
if char = namespace =~ /:(\w+)$/
command_name, namespace = $1, namespace.slice(0, char)
else
command_name = namespace
end
command_name, namespace = "help", "help" if command_name.blank? || HELP_MAPPINGS.include?(command_name)
command_name, namespace = "version", "version" if %w( -v --version ).include?(command_name)
command = find_by_namespace(namespace, command_name)
if command && command.all_commands[command_name]
command.perform(command_name, args, config)
else
find_by_namespace("rake").perform(full_namespace, args, config)
end
end
end
end
end
Con el comando server
, Rails ejecutará el siguiente código:
module Rails
module Command
class ServerCommand < Base # :nodoc:
def perform
extract_environment_option_from_argument
set_application_directory!
prepare_restart
Rails::Server.new(server_options).tap do |server|
# Require application after server sets environment to propagate
# the --environment option.
require APP_PATH
Dir.chdir(Rails.application.root)
if server.serveable?
print_boot_information(server.server, server.served_url)
after_stop_callback = -> { say "Exiting" unless options[:daemon] }
server.start(after_stop_callback)
else
say rack_server_suggestion(using)
end
end
end
end
end
end
Este archivo cambiará al directorio raíz de Rails (una ruta dos directorios arriba
de APP_PATH
que apunta aconfig / application.rb
), pero solo si el
No se encuentra el archivo config.ru
. Esto luego inicia la clase Rails :: Server
.
1.5 actionpack/lib/action_dispatch.rb
Action Dispatch es el componente de enrutamiento del marco de Rails. Agrega funcionalidad como enrutamiento, sesión y middlewares comunes.
1.6 rails/commands/server/server_command.rb
La clase Rails::Server
se define en este archivo heredando de
Rack::Server
. Cuando se llama a Rails::Server.new
, se llama a initialize
método en rails/commands/server/server_command.rb
:
module Rails
class Server < ::Rack::Server
def initialize(options = nil)
@default_options = options || {}
super(@default_options)
set_environment
end
end
end
En primer lugar, se llama a super
que llama al método initialize
en Rack::Server
.
1.7 Rack: lib/rack/server.rb
Rack::Server
es responsable de proporcionar una interfaz de servidor común para todas las aplicaciones basadas en Rack, de la que Rails ahora forma parte.
El método initialize
en Rack::Server
simplemente establece varias variables:
module Rack
class Server
def initialize(options = nil)
@ignore_options = []
if options
@use_default_options = false
@options = options
@app = options[:app] if options[:app]
else
argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
@use_default_options = true
@options = parse_options(argv)
end
end
end
end
En este caso, el valor de retorno de Rails :: Command :: ServerCommand # server_options
se asignará aoptions
.
Cuando se evalúan las líneas dentro de la instrucción if, se establecerán un par de variables de instancia.
El método server_options
enRails :: Command :: ServerCommand
se define de la siguiente manera:
module Rails
module Command
class ServerCommand
no_commands do
def server_options
{
user_supplied_options: user_supplied_options,
server: using,
log_stdout: log_to_stdout?,
Port: port,
Host: host,
DoNotReverseLookup: true,
config: options[:config],
environment: environment,
daemonize: options[:daemon],
pid: pid,
caching: options[:dev_caching],
restart_cmd: restart_command,
early_hints: early_hints
}
end
end
end
end
end
El valor se asignará a la variable de instancia @ options
.
Después de que super
haya terminado en Rack::Server
, volvemos a
rails/commands/server/server_command.rb
. En este punto, set_environment
se llama dentro del contexto del objeto Rails::Server
.
module Rails
module Server
def set_environment
ENV["RAILS_ENV"] ||= options[:environment]
end
end
end
Después de que haya finalizado initialize
, volvemos al comando del servidor
donde se requiere APP_PATH
(que se configuró anteriormente).
1.8 config/application
Cuando se ejecuta require APP_PATH
, se carga config/application.rb
(recordar
que APP_PATH
está definido en bin/rails
). Este archivo existe en su aplicación
y es gratis para que cambie según sus necesidades.
1.9 Rails::Server#start
Después de cargar config/application
, se llama a server.start
. Este método es
definido así:
module Rails
class Server < ::Rack::Server
def start(after_stop_callback = nil)
trap(:INT) { exit }
create_tmp_directories
setup_dev_caching
log_to_stdout if options[:log_stdout]
super()
...
end
private
def setup_dev_caching
if options[:environment] == "development"
Rails::DevCaching.enable_by_argument(options[:caching])
end
end
def create_tmp_directories
%w(cache pids sockets).each do |dir_to_make|
FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make))
end
end
def log_to_stdout
wrapped_app # touch the app so the logger is set up
console = ActiveSupport::Logger.new(STDOUT)
console.formatter = Rails.logger.formatter
console.level = Rails.logger.level
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
end
end
end
end
Este método crea una trampa para las señales INT
, por lo que si CTRL-C
el servidor, saldrá del proceso.
Como podemos ver en el código aquí, creará el tmp/cache
,
Directorios tmp/pids
y tmp/sockets
. Luego habilita el almacenamiento en caché en desarrollo
si se llama a bin/rails server
con --dev-caching
. Finalmente, llama a wrap_app
que es
responsable de crear la aplicación Rack, antes de crear y asignar una instancia
de ActiveSupport::Logger
.
El método super
llamará a Rack::Server.start
que comienza su definición de la siguiente manera:
module Rack
class Server
def start &blk
if options[:warn]
$-w = true
end
if includes = options[:include]
$LOAD_PATH.unshift(*includes)
end
if library = options[:require]
require library
end
if options[:debug]
$DEBUG = true
require "pp"
p options[:server]
pp wrapped_app
pp app
end
check_pid! if options[:pid]
# Touch the wrapped app, so that the config.ru is loaded before
# daemonization (i.e. before chdir, etc).
handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
wrapped_app
end
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
end
end
La parte interesante de una aplicación Rails es la última línea, server.run
. Aquí nos encontramos con el método wrap_app
nuevamente, que esta vez
vamos a explorar más (a pesar de que se ejecutó antes, y
así memorizado por ahora).
module Rack
class Server
def wrapped_app
@wrapped_app ||= build_app app
end
end
end
El método app
aquí se define así:
module Rack
class Server
def app
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
end
...
private
def build_app_and_options_from_config
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
@options.merge!(options) { |key, old, new| old }
app
end
def build_app_from_string
Rack::Builder.new_from_string(self.options[:builder])
end
end
end
El valor options[:config]
predeterminado es config.ru
que contiene esto:
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
run Rails.application
El método Rack::Builder.parse_file
aquí toma el contenido de este archivo config.ru
y lo analiza usando este código:
module Rack
class Builder
def self.load_file(path, opts = Server::Options.new)
...
app = new_from_string cfgfile, config
...
end
...
def self.new_from_string(builder_script, file="(rackup)")
eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
TOPLEVEL_BINDING, file, 0
end
end
end
El método initialize
de Rack::Builder
tomará el bloque aquí y lo ejecutará dentro de una instancia de Rack :: Builder
.
Aquí es donde ocurre la mayor parte del proceso de inicialización de Rails.
La línea require
paraconfig/environment.rb
en config.ru
es la primera en ejecutarse:
require_relative "config/environment"
1.10 config/environment.rb
Este archivo es el archivo común requerido por config.ru
(bin/rails server
) y Passenger. Aquí es donde se encuentran estas dos formas de ejecutar el servidor; todo antes de este punto ha sido la configuración de Rack and Rails.
Este archivo comienza requiriendo config/application.rb
:
require_relative "application"
1.11 config/application.rb
Este archivo requiere config/boot.rb
:`
require_relative "boot"
Pero solo si no se ha requerido antes, que sería el caso en bin/rails server
pero no sería el caso de Passenger.
¡Entonces comienza la diversión!
2 Loading Rails
La siguiente línea en config/application.rb
es:
require "rails/all"
2.1 railties/lib/rails/all.rb
Este archivo es responsable de requerir todos los marcos individuales de Rails:
require "rails"
%w(
active_record/railtie
active_storage/engine
action_controller/railtie
action_view/railtie
action_mailer/railtie
active_job/railtie
action_cable/engine
action_mailbox/engine
action_text/engine
rails/test_unit/railtie
sprockets/railtie
).each do |railtie|
begin
require railtie
rescue LoadError
end
end
Aquí es donde se cargan todos los frameworks Rails y así se hacen disponible para la aplicación. No entraremos en detalles de lo que pasa dentro de cada uno de esos marcos, pero le recomendamos que intente Explórelos por su cuenta.
Por ahora, solo tenga en cuenta que la funcionalidad común, como los motores Rails, La configuración de I18n y Rails se define aquí.
2.2 Back to config/environment.rb
El resto de config/application.rb
define la configuración del
Rails::Application
que se utilizará una vez que la aplicación esté completamente
inicializado. Cuando config/application.rb
haya terminado de cargar Rails y definido
el espacio de nombres de la aplicación, volvemos a config/environment.rb
. Aquí el
la aplicación se inicializa con Rails.application.initialize!
, que es
definido en rails/application.rb
.
2.3 railties/lib/rails/application.rb
El método initialize!
Se ve así:
def initialize!(group = :default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
Comentarios Sobre el Contenido
Las guías de rieles se administran y publican en latinadeveloper/railsguides.es en GitHub.
Si lee esta guía y encuentra algún texto o código incorrecto que le interese, no dude en enviar una solicitud de extracción en el repositorio anterior. Consulte el archivo README en GitHub para saber cómo enviar una solicitud de extracción. Please contribute if you see any typos or factual errors.