Инициализатор Rails, который запускает * после * маршрутов, загружается?
Я хочу установить атрибут класса при запуске приложения Rails. Он требует проверки некоторых маршрутов, поэтому маршруты должны быть загружены до запуска моего пользовательского кода. У меня возникли проблемы с поиском надежного места для подключения.
Это работает ОТЛИЧНО в среде "test":
config.after_initialize do
Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}"
end
Но он не работает в среде разработки (маршруты пусты)
На данный момент у меня, похоже, есть вещи, работающие в режиме разработки, запустив тот же код в config.to_prepare
, который, как я понимаю, происходит до каждого запроса. К сожалению, использование только to_prepare
не работает в тестовом режиме, следовательно, дублирование.
Мне любопытно, почему маршруты загружаются до after_initialize в тестовом режиме, но не в режиме разработки. И на самом деле, какой лучший крючок для этого? Есть ли один крючок, который будет работать для всех сред?
* EDIT *
Предложение о перезагрузке маршрутов было большим. Это дало мне постоянный доступ к маршрутам внутри after_initialize во всех средах. Однако для моего варианта использования, я думаю, мне все равно нужно запустить код из to_prepare, так как я устанавливаю атрибут класса на модели и модели перезагружаются перед каждым запросом.
Итак, вот что я сделал.
[:after_initialize, :to_prepare].each do |hook|
config.send(hook) do
User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq
end
end
Мне кажется немного беспорядочным. Я думаю, я бы предпочел сделать что-то вроде:
config.after_initialize do
User.exclude_routes_from_usernames!
end
config.to_prepare do
User.exclude_routes_from_usernames!
end
Но я не уверен, что User
- это подходящее место для изучения Rails.application.routes
. Думаю, я мог бы сделать то же самое с кодом в lib/, но я не уверен, что это так.
Другой вариант - просто применить предложение mu на to_prepare. Это работает, но кажется, что заметная задержка перезагружает маршруты по каждому запросу в моей среде dev, поэтому я не уверен, что это хороший вызов, хотя он DRY, по крайней мере.
config.to_prepare do
Rails.application.reload_routes!
User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("\n").scan(/\s\/(\w+)/).flatten.compact.uniq
end
Ответы
Ответ 1
Вы можете заставить маршруты загружаться, прежде чем смотреть на Rails.application.routes
следующим образом:
Rails.application.reload_routes!
Попробуйте это в config/application.rb
:
config.after_initialize do
Rails.application.reload_routes!
Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}"
end
Я делал схожие вещи, необходимые для проверки маршрутов (для конфликтов с маршрутами /:slug
), и в итоге я положил reload_routes!
и проверил в config.after_initialize
, как вы делаете.
Ответ 2
Если вы пытаетесь запустить код в инициализаторе после загрузки маршрутов, вы можете попробовать использовать параметр after:
:
initializer "name_of_initializer", after: :add_routing_paths do |app|
# do custom logic here
end
Здесь можно найти события инициализации: http://guides.rubyonrails.org/configuring.html#initialization-events