Рельсы:фильтр, определенный в файле lib, требуемом в файле Environment.rb, исчезает из filter_chain в производственной среде.Почему?

StackOverflow https://stackoverflow.com/questions/620146

Вопрос

В моем приложении Rails у меня есть файл в библиотеке, который, помимо прочего, устанавливает фильтр, работающий на всех контроллерах.

При работе в среде разработки все работает нормально.Однако при производстве фильтр пропадает.Забавно то, что, проверив filter_chain, я заметил, что другие фильтры остаются, например.те, которые определены в плагинах или позже в конкретном классе контроллера.

Я тестировал это как с Rails Edge, так и с версией 2.3.0.

Тестирование обновления:

Теперь я протестировал старые рельсы и обнаружил, что проблема присутствует еще в версии 2.1.0, но не в версии 2.0.5. Я разделил их пополам и нашел 986aec5 рельсы обязуются быть виновными.


Я изолировал это поведение в следующем крошечном тестовом примере:

# 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'

Вот результат, который я получаю при работе под разработка среда:

$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter

И вот результат для производство среда:

$ script/server -e production &
$ curl localhost:3000/foo             
> not filtered

Как упоминалось ранее, он отлично работает в любой среде, когда я делаю то же самое через плагин.Все, что мне нужно, это положить то, что находится под lib/foobar.rb в плагине init.rb файл.

В каком-то смысле у меня уже есть обходной путь, но я хотел бы понять, что происходит и почему фильтр пропадает во время производства.

Я предполагаю, что дело в том, что Rails обрабатывает загрузку по-разному в разных средах, но мне нужно копнуть глубже.

обновлять

Действительно, теперь я сузил его до следующей строки конфигурации:

config.cache_classes = false

Если в production.rb, config.cache_classes изменено с true к false, тестовое приложение работает правильно.

Я все еще задаюсь вопросом, почему перезагрузка классов вызывает такие вещи.

Это было полезно?

Решение

Фредерик Чунг на Список рельсов имел ответ:

Потому что кэш_классы делает нечто большее.Путь перед работой фильтров, если Foo <бар, то только те фильтры, определенные в баре в этот момент, будут унаследованы Foo - добавление их в бар на более позднее срок

В режиме разработки приложение запускается, ваш файл требуется, фильтр, добавленный в ActionController :: Base.Позже появляется первый запрос, контроллер загружается, и он наследует этот фильтр.

Когда Cache_Classes верно, все ваши классы приложения загружаются заранее.Это происходит до того, как ваш файл будет необходим, поэтому все ваши контроллеры уже существуют, когда этот файл запускается, и поэтому он не имеет никакого эффекта.Вы можете решить это, требуя этого файла из инициализатора (гарантируя, что он запускается до загрузки классов приложений), но на самом деле, почему вы просто поместили это в Application.rb?

Фред


Мой реальный случай на самом деле был гораздо более сложным, и я нашел способ решить проблему:

config.after_initialize do
  require 'foobar'
end

А after_initialize блок запускается после инициализации платформы, но до загрузки файлов приложения, следовательно, это повлияет ActionPack::Base после загрузки, но до того, как будут загружены контроллеры приложений.

Я думаю, что это в целом безопасный способ справиться со всей предварительной загрузкой, которая происходит в производстве.

Другие советы

Вставьте Ruby-скрипт

RAILS_ROOT\config\инициализаторы

который содержит

require "foobar.rb"

Это вызывает у меня before_filter.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top