Инициализатор 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