Как подключиться к Rails * после того, как * файлы перезагружаются по каждому запросу в режиме разработки?
Я работаю над gem, который динамически устанавливает свойства на моделях ActiveRecord (например, table_name
) на основе пользовательской конфигурации.
У меня есть инициализатор, который достигает этого. Однако моя проблема заключается в том, что в режиме dev эти классы перезагружаются, поэтому они не поддерживают эти значения.
Итак, я подумал, что я использую railtie, чтобы подключиться к точке, где эти файлы перезагружены, и снова запустите мою конфигурацию на моделях. Моя проблема, однако, в том, что config.to_prepare
в railtie, кажется, работает до того, как reload!
действительно имеет место. Я могу доказать это с небольшим количеством протоколирования:
module MyMod
class Railtie < Rails::Railtie
config.to_prepare do
Rails.logger.debug("Contact object_id: #{Contact.object_id}")
end
end
end
Если я загружу свою консоль, я получаю первый журнал:
Contact object_id: 2202692040
Если я проверяю Contact.object_id
, это соответствует:
Contact.object_id #=> 2202692040
Тогда я reload!
reload!
Логгер Rails из моих журналов to_prepare
:
Contact object_id: 2202692040
Итак, у него все еще есть старый объект_ид, но когда я проверяю его на консоли:
Contact.object_id #=> 2197355080
Который является вновь загруженным идентификатором объекта класса.
Итак, как мне получить to_prepare
для запуска после перезагрузки файлов? Используя Rails 3.0.10
Обновление
Я также попытался вручную связать это действие с обратным вызовом after_prepare
на ActionDispatch::Callbacks
следующим образом:
initializer "apartment.init" do
ActionDispatch::Callbacks.set_callback(:prepare, :after) do
Rails.logger.debug("Contact object_id: #{Contact.object_id}")
end
end
Он действительно выполняет обратный вызов после config.to_prepare
, но по-прежнему происходит before
файлы перезагружаются... Я получаю то же поведение, что и выше.
Ответы
Ответ 1
Напишите инициализатор, который, если cache_classes
равен false
, использует ActionDispatch::Reloader
для установки обратного вызова to_prepare
который запускает вашу процедуру установки gem.
initializer 'foobar.install' do
if Rails.configuration.cache_classes
FooBar.install!
else
ActionDispatch::Reloader.to_prepare do
FooBar.install!
end
end
end
Это будет работать как в консоли с reload!
метод и в стойке сервера приложений.
Ответ 2
Я считаю, что перезагрузщик Rails только отцепляет константы. Модели перезагружаются автозагрузкой, когда константы ссылаются в вашем приложении.
В вашем обратном вызове я думаю, что вы должны запускать загрузку вручную, ссылаясь на все модели. Возможно, ваш драгоценный камень может содержать список всех моделей, которые включают его, а затем просто ссылается на константы, чтобы их автозагрузить...
model_names.each { |model_name| model_name.constantize }
Вы можете создать список self.included
:
module MyGem
self.included(base)
@model_names ||= Set.new
@model_names += base.to_s
end
end