Я работаю над приложением 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
каталог: контроллеры, модели и т. д. Эти файлы перезагружаются в режиме разработки при каждом запросе.Поэтому конфигурация, подобная моему примеру выше, теряется.
Введите to_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
?Я боюсь, что вызов его несколько раз перезапишет предыдущие блоки.
Обновление
Как упоминал @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
работал с перебоями в процессе разработки.