Trilhos:o filtro definido no arquivo lib exigido em Environment.rb desaparece de filter_chain no ambiente de produção.Por que?
-
03-07-2019 - |
Pergunta
Na minha aplicação Rails, tenho um arquivo em lib que, entre outras coisas, configura um filtro que roda em todos os controladores.
Ao executar em ambiente de desenvolvimento, tudo funciona bem.No entanto, em produção, o filtro desaparece.O engraçado é que, ao inspecionar o filter_chain
, notei que outros filtros permanecem, por exemplo.aqueles definidos em plug-ins ou posteriormente na classe de controlador específica.
Eu testei isso com Rails Edge e v2.3.0.
Atualização de teste:
Agora testei com trilhos mais antigos e descobri que o problema estava presente na v2.1.0, mas não na v2.0.5, eu os dividi ao meio e encontrei o 986aec5 Rails se compromete a ser culpado.
Isolei o comportamento para o seguinte pequeno caso de teste:
# 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'
Aqui está a saída que recebo ao executar sob o desenvolvimento ambiente:
$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter
E aqui está a saída para o Produção ambiente:
$ script/server -e production &
$ curl localhost:3000/foo
> not filtered
Como mencionado anteriormente, funciona bem em qualquer ambiente quando faço a mesma coisa via plugin.Tudo que eu preciso é colocar o que está embaixo lib/foobar.rb
no plugin init.rb
arquivo.
De certa forma, já tenho uma solução alternativa, mas gostaria de entender o que está acontecendo e o que está causando a falta do filtro durante a produção.
Suponho que seja algo nas diferentes maneiras como o Rails lida com o carregamento em diferentes ambientes, mas preciso me aprofundar.
atualizar
Na verdade, agora reduzi-o à seguinte linha de configuração:
config.cache_classes = false
Se, em production.rb
, config.cache_classes
é alterado de true
para false
, o aplicativo de teste funcionará corretamente.
Ainda me pergunto por que o recarregamento da classe está causando tal coisa.
Solução
Frederick Cheung no Lista de trilhos tive a resposta:
Porque cache_classes faz um pouco mais do que isso.O caminho antes dos filtros funcionar, se Foo <bar, apenas os filtros definidos em bar naquele ponto serão herdados por Foo - adicionando -os à barra posteriormente não fará nada
No modo de desenvolvimento, o aplicativo é iniciado, seu arquivo é necessário, o filtro adicionado ao ActionController :: Base.Mais tarde, a primeira solicitação aparece, o controlador é carregado e herda esse filtro.
Quando o cache_classes é verdadeiro, todas as suas classes de aplicativos são carregadas com antecedência.Isso acontece antes que seu arquivo seja necessário; portanto, todos os seus controladores já existem quando esse arquivo é executado e, portanto, não tem efeito.Você pode resolver isso exigindo esse arquivo de um inicializador (garantindo que ele seja executado antes que as classes de aplicativos sejam carregadas), mas realmente por que você não colocaria isso no application.rb?
Fred
Meu caso real era bem mais complicado, e foi assim que encontrei para resolver o problema:
config.after_initialize do
require 'foobar'
end
O after_initialize
O bloco é executado após a inicialização da estrutura, mas antes de carregar os arquivos do aplicativo, portanto, afetará ActionPack::Base
depois de ter sido carregado, mas antes dos controladores do aplicativo.
Acho que essa é a maneira geralmente segura de lidar com todo o pré-carregamento que ocorre na produção.
Outras dicas
Solte um script de rubi em
Rails_root Config Inicializadores
Isso contém
require "foobar.rb"
Isso chama o antes_filter para mim.