Я работаю над приложением Rails, которое использует движок. Я использую инициализатор для настройки одного из моих контроллеров ядра, чтобы он вызывал действие в главном приложении. Код выглядит примерно так:
# config/initializers/my_engine.rb
MyEngine::SomeController.after_filter proc {
# Do something in the host app
}, :only => :update
Это отлично работает в процессе производства, но в режиме разработки proc вызывается только при первом запросе. Это связано с тем, что классы перезагружаются, и эта конфигурация теряется, поскольку она хранилась в переменной класса. (Например, MyEngine::SomeController
перезагружается из файла, в котором он находится, а поскольку after_filter
не объявлен там, он не добавляется обратно.)
Некорректный фон Rails
В режиме разработки Rails использует следующую стратегию загрузки:
- Код в каталоге
app
перезагружается по каждому запросу, исходя из предположения, что вы активно меняете его. - Код в каталоге
lib
вместе сconfig/initializer
файлами загружается один раз, когда приложение загружается.
Файлы инициализатора обычно используются для настройки драгоценных камней. Раньше у камней в основном был код в каталоге lib
, поэтому выполнение их конфигурации было достаточно.
Как двигатели меняют вещи
Тем не менее, у двигателей Rails есть код в каталоге app
: контроллеры, модели и т.д. Эти файлы перезагружаются в режиме разработки по каждому запросу. Поэтому конфигурация, подобная приведенному выше примеру, теряется.
Введите в_prepare
Rails предоставляет config.to_prepare
специально для решения этой проблемы: он запускается один раз в процессе производства и по каждому запросу в разработке.
Например, мы имеем это в application.rb, который отлично работает:
config.to_prepare do
# set up class variables (after_filters, etc)
end
Однако, если мне нужно сконфигурировать конфигурацию всех моих двигателей в application.rb
, это победит точку config/initializers
, если все будет организовано.
Итак, для любой конфигурации классов в каталогах моих двигателей app
я хочу поместить этот код в файлы под config/initializers
.
Вот мои вопросы.
- Непонятно, как получить
config
в область видимости в файле инициализации. Я думаю, что это будетRails.application.config
. Это правильно? - Можно ли добавить несколько блоков
to_prepare
? Боюсь, что вызов его несколько раз перезапишет предыдущие блоки.
Update
Как отметил @Frederick Cheung, Rails.application.config.to_prepare
работает в файлах config/initializer
, и можно использовать столько из них, сколько необходимо в различных файлах; каждый вызов добавляет свой блок к массиву, поэтому ничего не перезаписывается.
Итак, решение этой проблемы:
# config/initializers/my_engine.rb
Rails.application.config.to_prepare do
MyEngine::SomeController.after_filter proc {
# Do something in the host app
}, :only => :update
end
Одна вещь, которая по-прежнему кажется странной: я ожидал, что блок to_prepare
будет вызываться в каждом запросе в режиме разработки, но вместо этого он называется случайным образом каждый третий запрос или так. Я добавил блок:
Rails.application.config.to_prepare do
Rails.logger.info "Running the prepare block!"
end
... перезапустил мое приложение и обновил страницу девять раз. Я видел сообщение только на 1-м, 5-м, 7-м и 9-м запросах. Я не уверен, что объясняет это поведение, но объясняет, почему мой код без to_prepare
работал с перерывами в разработке.