ADVERTENCIA: Esta guía asume un conocimiento práctico del protocolo Rack y conceptos de Rack como middlewares, mapas de URL y Rack::Builder
.
1 Introducción a Rack
Rack proporciona una interfaz mínima, modular y adaptable para desarrollar aplicaciones web en Ruby. Al envolver solicitudes y respuestas HTTP de la manera más simple posible, unifica y destila la API para servidores web, frameworks web y software intermedio (el llamado middleware) en una única llamada de método.
Explicar cómo funciona Rack no está realmente en el alcance de esta guía. En caso de que no estés familiarizado con los conceptos básicos de Rack, deberías consultar la sección de Recursos a continuación.
2 Rails sobre Rack
2.1 Objeto Rack de la Aplicación Rails
Rails.application
es el objeto principal de la aplicación Rack de una aplicación Rails. Cualquier servidor web compatible con Rack debería usar el objeto Rails.application
para servir una aplicación Rails.
2.2 bin/rails server
bin/rails server
realiza la tarea básica de crear un objeto Rack::Server
y comenzar el servidor web.
Así es como bin/rails server
crea una instancia de Rack::Server
:
Rails::Server.new.tap do |server|
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
end
El Rails::Server
hereda de Rack::Server
y llama al método Rack::Server#start
de esta manera:
class Server < ::Rack::Server
def start
# ...
super
end
end
2.3 rackup
Para usar rackup
en lugar de bin/rails server
de Rails, puedes poner lo siguiente dentro de config.ru
en el directorio raíz de tu aplicación Rails:
# Rails.root/config.ru
require_relative "config/environment"
run Rails.application
Y comenzar el servidor:
$ rackup config.ru
Para obtener más información sobre las diferentes opciones de rackup
, puedes ejecutar:
$ rackup --help
2.4 Desarrollo y Recarga Automática
Los middlewares se cargan una vez y no se monitorean para cambios. Tendrás que reiniciar el servidor para que los cambios se reflejen en la aplicación en ejecución.
3 Pila de Middleware de Action Dispatcher
Muchos de los componentes internos de Action Dispatcher se implementan como middlewares de Rack. Rails::Application
usa ActionDispatch::MiddlewareStack
para combinar varios middlewares internos y externos para formar una aplicación Rack completa de Rails.
NOTA: ActionDispatch::MiddlewareStack
es el equivalente de Rails a Rack::Builder
, pero está construido para ofrecer mejor flexibilidad y más características para satisfacer los requisitos de Rails.
3.1 Inspeccionando la Pila de Middleware
Rails tiene un comando útil para inspeccionar la pila de middleware en uso:
$ bin/rails middleware
Para una aplicación Rails recién generada, esto podría producir algo como:
use ActionDispatch::HostAuthorization
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActionDispatch::ServerTiming
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Sprockets::Rails::QuietAssets
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::ActionableExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run MyApp::Application.routes
Los middlewares predeterminados que se muestran aquí (y algunos otros) se resumen en la sección de Middlewares Internos a continuación.
3.2 Configurando la Pila de Middleware
Rails proporciona una interfaz de configuración simple config.middleware
para agregar, eliminar y modificar los middlewares en la pila de middleware a través de application.rb
o el archivo de configuración específico del entorno environments/<environment>.rb
.
3.2.1 Agregando un Middleware
Puedes agregar un nuevo middleware a la pila de middleware usando cualquiera de los siguientes métodos:
config.middleware.use(new_middleware, args)
- Agrega el nuevo middleware al final de la pila de middleware.config.middleware.insert_before(existing_middleware, new_middleware, args)
- Agrega el nuevo middleware antes del middleware existente especificado en la pila de middleware.config.middleware.insert_after(existing_middleware, new_middleware, args)
- Agrega el nuevo middleware después del middleware existente especificado en la pila de middleware.
# config/application.rb
# Agrega Rack::BounceFavicon al final
config.middleware.use Rack::BounceFavicon
# Agrega Lifo::Cache después de ActionDispatch::Executor.
# Pasa el argumento { page_cache: false } a Lifo::Cache.
config.middleware.insert_after ActionDispatch::Executor, Lifo::Cache, page_cache: false
3.2.2 Intercambiando un Middleware
Puedes intercambiar un middleware existente en la pila de middleware usando config.middleware.swap
.
# config/application.rb
# Reemplaza ActionDispatch::ShowExceptions con Lifo::ShowExceptions
config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions
3.2.3 Moviendo un Middleware
Puedes mover un middleware existente en la pila de middleware usando config.middleware.move_before
y config.middleware.move_after
.
# config/application.rb
# Mueve ActionDispatch::ShowExceptions antes de Lifo::ShowExceptions
config.middleware.move_before Lifo::ShowExceptions, ActionDispatch::ShowExceptions
# config/application.rb
# Mueve ActionDispatch::ShowExceptions después de Lifo::ShowExceptions
config.middleware.move_after Lifo::ShowExceptions, ActionDispatch::ShowExceptions
3.2.4 Eliminando un Middleware
Agrega las siguientes líneas a tu configuración de la aplicación:
# config/application.rb
config.middleware.delete Rack::Runtime
Y ahora, si inspeccionas la pila de middleware, encontrarás que Rack::Runtime
no es parte de ella.
$ bin/rails middleware
(in /Users/lifo/Rails/blog)
use ActionDispatch::Static
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8>
...
run Rails.application.routes
Si deseas eliminar middleware relacionado con sesiones, haz lo siguiente:
# config/application.rb
config.middleware.delete ActionDispatch::Cookies
config.middleware.delete ActionDispatch::Session::CookieStore
config.middleware.delete ActionDispatch::Flash
Y para eliminar middleware relacionado con el navegador,
# config/application.rb
config.middleware.delete Rack::MethodOverride
Si deseas que se genere un error cuando intentes eliminar un elemento inexistente, usa delete!
en su lugar.
# config/application.rb
config.middleware.delete! ActionDispatch::Executor
3.3 Pila de Middleware Interno
Gran parte de la funcionalidad de Action Controller se implementa como Middlewares. La siguiente lista explica el propósito de cada uno de ellos:
ActionDispatch::HostAuthorization
- Protege de ataques de re-binding de DNS permitiendo explícitamente los hosts a los que se puede enviar una solicitud. Consulta la guía de configuración para obtener instrucciones de configuración.
Rack::Sendfile
- Establece el encabezado X-Sendfile específico del servidor. Configura esto a través de la opción
config.action_dispatch.x_sendfile_header
.
ActionDispatch::Static
- Se utiliza para servir archivos estáticos desde el directorio público. Se desactiva si
config.public_file_server.enabled
esfalse
.
Rack::Lock
- Establece el indicador
env["rack.multithread"]
enfalse
y envuelve la aplicación dentro de un Mutex.
ActionDispatch::Executor
- Se utiliza para la recarga de código segura para hilos durante el desarrollo.
ActionDispatch::ServerTiming
- Establece un encabezado
Server-Timing
que contiene métricas de rendimiento para la solicitud.
ActiveSupport::Cache::Strategy::LocalCache::Middleware
- Se utiliza para el almacenamiento en caché en memoria. Este caché no es seguro para hilos.
Rack::Runtime
- Establece un encabezado X-Runtime, que contiene el tiempo (en segundos) tomado para ejecutar la solicitud.
Rack::MethodOverride
- Permite que el método sea sobrescrito si
params[:_method]
está establecido. Este es el middleware que soporta los tipos de métodos HTTP PUT y DELETE.
ActionDispatch::RequestId
- Hace que un encabezado único
X-Request-Id
esté disponible para la respuesta y habilita el métodoActionDispatch::Request#request_id
.
ActionDispatch::RemoteIp
- Verifica ataques de suplantación de IP.
Sprockets::Rails::QuietAssets
- Suprime la salida del registrador para solicitudes de activos.
Rails::Rack::Logger
- Notifica a los registros que la solicitud ha comenzado. Después de que la solicitud se completa, vacía todos los registros.
ActionDispatch::ShowExceptions
- Rescata cualquier excepción devuelta por la aplicación y llama a una aplicación de excepciones que la envolverá en un formato para el usuario final.
ActionDispatch::DebugExceptions
- Responsable de registrar excepciones y mostrar una página de depuración en caso de que la solicitud sea local.
ActionDispatch::ActionableExceptions
- Proporciona una forma de despachar acciones desde las páginas de error de Rails.
ActionDispatch::Reloader
- Proporciona callbacks de preparación y limpieza, destinados a ayudar con la recarga de código durante el desarrollo.
ActionDispatch::Callbacks
- Proporciona callbacks para ser ejecutados antes y después de despachar la solicitud.
ActiveRecord::Migration::CheckPending
- Verifica migraciones pendientes y genera
ActiveRecord::PendingMigrationError
si hay migraciones pendientes.
ActionDispatch::Cookies
- Establece cookies para la solicitud.
ActionDispatch::Session::CookieStore
- Responsable de almacenar la sesión en cookies.
ActionDispatch::Flash
- Configura las claves de flash. Solo está disponible si
config.session_store
está establecido en un valor.
ActionDispatch::ContentSecurityPolicy::Middleware
- Proporciona un DSL para configurar un encabezado Content-Security-Policy.
Rack::Head
- Devuelve un cuerpo vacío para todas las solicitudes HEAD. Deja todas las demás solicitudes sin cambios.
Rack::ConditionalGet
- Agrega soporte para "GET Condicional" para que el servidor responda con nada si la página no ha cambiado.
Rack::ETag
- Agrega encabezado ETag en todos los cuerpos de tipo String. Los ETags se utilizan para validar caché.
Rack::TempfileReaper
- Limpia archivos temporales utilizados para almacenar en búfer solicitudes multipart.
CONSEJO: Es posible usar cualquiera de los middlewares anteriores en tu pila de Rack personalizada.
4 Recursos
4.1 Aprendiendo Rack
4.2 Entendiendo Middlewares
Comentarios
Se te anima a ayudar a mejorar la calidad de esta guía.
Por favor contribuye si ves algún error tipográfico o errores fácticos. Para comenzar, puedes leer nuestra sección de contribuciones a la documentación.
También puedes encontrar contenido incompleto o cosas que no están actualizadas. Por favor agrega cualquier documentación faltante para main. Asegúrate de revisar Guías Edge primero para verificar si los problemas ya están resueltos o no en la rama principal. Revisa las Guías de Ruby on Rails para estilo y convenciones.
Si por alguna razón detectas algo que corregir pero no puedes hacerlo tú mismo, por favor abre un issue.
Y por último, pero no menos importante, cualquier tipo de discusión sobre la documentación de Ruby on Rails es muy bienvenida en el Foro oficial de Ruby on Rails.