Rieles:El filtro definido en el archivo lib requerido en Environment.rb desaparece de filter_chain en el entorno de producción.¿Por qué?
-
03-07-2019 - |
Pregunta
En mi aplicación Rails, tengo un archivo en lib que, entre otras cosas, configura un filtro que se ejecuta en todos los controladores.
Cuando se ejecuta en un entorno de desarrollo, todo funciona bien.Sin embargo, durante el proceso de producción el filtro desaparece.Lo curioso es que, al inspeccionar el filter_chain
, Noté que permanecen otros filtros, por ejemplo.aquellos definidos en complementos, o más adelante en la clase de controlador específica.
Probé esto tanto con Rails Edge como con v2.3.0.
Actualización de prueba:
Ahora probé con rieles más antiguos y descubrí que el problema estaba presente en la versión 2.1.0, pero no en la versión 2.0.5, los dividí en dos y encontré el 986aec5 Rails se compromete a ser culpable.
He aislado el comportamiento en el siguiente pequeño caso de prueba:
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
render :text => 'not filtered'
end
end
# lib/foobar.rb
ActionController::Base.class_eval do
before_filter :foobar
def foobar
render :text => 'hi from foobar filter'
end
end
# config/environment.rb (at end of file)
require 'foobar'
Aquí está el resultado que obtengo cuando ejecuto bajo el desarrollo ambiente:
$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter
Y aquí está el resultado del producción ambiente:
$ script/server -e production &
$ curl localhost:3000/foo
> not filtered
Como se mencionó anteriormente, funciona bien en cualquier entorno cuando hago lo mismo mediante un complemento.Todo lo que necesito es poner lo que hay debajo lib/foobar.rb
en el complemento init.rb
archivo.
Entonces, en cierto modo, ya tengo una solución alternativa, pero me gustaría entender qué está pasando y qué está causando que el filtro desaparezca cuando está en producción.
Supongo que se debe a las diferentes formas en que Rails maneja la carga en los diferentes entornos, pero necesito profundizar más.
actualizar
De hecho, ahora lo he reducido a la siguiente línea de configuración:
config.cache_classes = false
Si, en production.rb
, config.cache_classes
se cambia de true
a false
, la aplicación de prueba funciona correctamente.
Todavía me pregunto por qué la recarga de clases está causando tal cosa.
Solución
Frederick Cheung en la Lista de rieles tenía la respuesta :
Porque cache_classes hace un poco más que eso. La manera antes de que funcionen los filtros, si Foo < Barra entonces solo aquellos filtros definidos en La barra en ese punto será heredada por Foo, agregándola a la barra en un una fecha posterior no hará nada
En el modo de desarrollo, se inicia la aplicación, se requiere su archivo, el filtro agregado a ActionController :: Base. Más tarde llega la primera solicitud, el controlador se carga y hereda ese filtro.
Cuando cache_classes es verdadero, todas sus clases de aplicación son cargado de antemano. Esto sucede antes de que se requiera su archivo, así que todos sus controladores ya existen cuando se ejecuta ese archivo y por lo tanto no tiene efecto. Puede resolver esto requiriendo este archivo de un inicializador (asegurándose de que se ejecuta antes de cargar las clases de la aplicación), pero ¿Por qué no lo pondrías en application.rb?
Fred
Mi caso real fue mucho más complicado, y esta es la forma en que encontré para resolver el problema:
config.after_initialize do
require 'foobar'
end
El bloque after_initialize
se ejecuta después de que se haya inicializado el marco pero antes de que cargue los archivos de la aplicación, por lo tanto, afectará a ActionPack::Base
después de que se haya cargado, pero antes de que lo estén los controladores de la aplicación.
Supongo que esa es la forma generalmente segura de lidiar con toda la precarga que se produce en la producción.
Otros consejos
Coloca un script Ruby en
RAILS_ROOT\config\inicializadores
eso contiene
require "foobar.rb"
Esto invoca el before_filter por mí.