Des rails:le filtre défini dans le fichier lib requis dans environnement.rb disparaît de filter_chain dans l'environnement de production.Pourquoi?
-
03-07-2019 - |
Question
Dans mon application Rails, j'ai un fichier dans lib qui, entre autres, configure un filtre qui s'exécute sur tous les contrôleurs.
Lors de l'exécution dans un environnement de développement, tout fonctionne bien.Cependant, en cours de production, le filtre disparaît.Ce qui est drôle, c'est qu'en inspectant le filter_chain
, j'ai remarqué que d'autres filtres restent, par exemple.ceux définis dans les plugins, ou plus tard dans la classe de contrôleur spécifique.
J'ai testé cela avec Rails Edge et v2.3.0.
Mise à jour des tests :
J'ai maintenant testé avec des rails plus anciens et j'ai trouvé que le problème était présent dans la v2.1.0, mais pas dans la v2.0.5, je les ai divisés en deux et j'ai trouvé le 986aec5 les rails s'engagent à être coupables.
J'ai isolé le comportement du petit cas de test suivant :
# 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'
Voici le résultat que j'obtiens lors de l'exécution sous le développement environnement:
$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter
Et voici le résultat du production environnement:
$ script/server -e production &
$ curl localhost:3000/foo
> not filtered
Comme mentionné précédemment, cela fonctionne bien pour n'importe quel environnement lorsque je fais la même chose via un plugin.Tout ce dont j'ai besoin c'est de mettre ce qu'il y a en dessous lib/foobar.rb
dans le plugin init.rb
déposer.
Donc, d'une certaine manière, j'ai déjà une solution de contournement, mais j'aimerais comprendre ce qui se passe et ce qui cause la disparition du filtre en production.
Je suppose que cela tient aux différentes manières dont Rails gère le chargement dans les différents environnements, mais je dois creuser plus profondément.
mise à jour
En effet, je l'ai maintenant réduit à la ligne de configuration suivante :
config.cache_classes = false
Si, dans production.rb
, config.cache_classes
est changé de true
à false
, l'application de test fonctionne correctement.
Je me demande toujours pourquoi le rechargement des classes provoque une telle chose.
La solution
Frederick Cheung sur la la liste de messagerie avait la réponse :
Parce que cache_classes fait un peu plus que cela. Le chemin avant que les filtres ne fonctionnent, si Foo < Bar alors seulement les filtres définis dans Foo héritera de Bar à ce moment - en les ajoutant à Bar à un moment donné. date ultérieure ne fera rien
En mode de développement, l'application démarre, votre fichier est requis, le filtre ajouté à ActionController :: Base. Plus tard, la première demande arrive, le contrôleur est chargé et il hérite de ce filtre.
Lorsque cache_classes a la valeur true, toutes vos classes d'application sont chargé à l'avance. Cela se produit avant que votre fichier soit requis, donc tous vos contrôleurs existent déjà lorsque ce fichier est exécuté et donc n'a aucun effet. Vous pouvez résoudre ce problème en demandant ce fichier à un initializer (s’assurer qu’il s’exécute avant le chargement des classes d’application), mais vraiment pourquoi ne voudriez-vous pas simplement mettre cela dans application.rb?
Fred
Mon cas réel était bien plus complexe et voici comment j'ai trouvé le moyen de résoudre le problème:
config.after_initialize do
require 'foobar'
end
Le bloc after_initialize
est exécuté après l’initialisation de la structure mais avant le chargement des fichiers de l’application; par conséquent, il affectera ActionPack::Base
une fois chargé, mais avant les contrôleurs d’application.
Je suppose que c'est le moyen généralement sûr de gérer tout le préchargement de la production.
Autres conseils
Déposez un script Ruby dans
RAILS_ROOT\config\initialiseurs
cela contient
require "foobar.rb"
Cela appelle le before_filter pour moi.