Как я могу предотвратить потерю конфигурации инициализатора в режиме разработки? - PullRequest
18 голосов
/ 17 января 2012

Я работаю над приложением 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 работал с перебоями в процессе разработки.

Ответы [ 2 ]

10 голосов
/ 17 января 2012

Вы можете добавить столько блоков to_prepare, сколько хотите - когда вы делаете config.to_prepare, Rails делает (в configuration.rb в railties)

def to_prepare(&blk)
  to_prepare_blocks << blk if blk
end

и затем перебирает те блоки, передающие их ActionDispatch::Reloader, где to_prepare реализуется с использованием ActiveSupport::Callbacks (то есть то же самое, что используется для before_save и т. Д.). Несколько to_prepare блоков в порядке.

В настоящее время похоже, что Rails перебирает to_prepare_blocks после чтения инициализаторов приложения, поэтому добавление в Rails.application.configuration.to_prepare должно работать. Вы можете предпочесть использовать ActionDispatch::Reloader.to_prepare.

1 голос
/ 03 апреля 2015

Ничто не мешает вам выполнить код инициализатора в файле, который находится в приложении / models.

, например

class MyClass
  def self.run_me_when_the_class_is_loaded
  end
end

MyClass.run_me_when_the_class_is_loaded

MyClass.run_me ... будет работать, когда классзагружен .... что нам и нужно, верно?

Не уверен, что это путь Rails .... но он чрезвычайно прост и не зависит от сдвигающихся ветров Rails.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...