15

Quiero establecer un atributo de clase cuando se inicia mi aplicación Rails. Requiere inspeccionar algunas rutas, por lo que las rutas deben cargarse antes de que se ejecute mi código personalizado. Estoy teniendo problemas para encontrar un lugar confiable para enganchar enInicializador de rieles que se ejecuta * después de que se carguen las rutas?

Esta aplicación funciona perfectamente en el entorno de "prueba":.

config.after_initialize do 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

Pero no trabajo en el entorno de "desarrollo" (las rutas están vacíos)

Por ahora parece que tengo cosas que funcionan en modo de desarrollo ejecutando el mismo código en config.to_prepare que entiendo sucede antes de cada solicitud. Desafortunadamente, usar to_prepare solo no parece funcionar en modo de prueba, de ahí la duplicación.

Tengo curiosidad por saber por qué las rutas se cargan antes de after_initialize en modo de prueba, pero no en modo de desarrollo. Y realmente, ¿cuál es el mejor gancho para esto? ¿Hay un solo gancho que funcione para todos los entornos?

* * EDITAR sugerencia

de mu de recarga de las rutas era grande. Me dio acceso constante a las rutas dentro de after_initialize en todos los entornos. Para mi caso de uso, creo que todavía necesito ejecutar el código de to_prepare también, ya que estoy configurando un atributo de clase en un modelo y los modelos se vuelven a cargar antes de cada solicitud.

Así que esto es lo que terminé haciendo.

[: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 

Parece un poco complicado para mí. Creo que prefiero hacer algo como:

config.after_initialize do 
    User.exclude_routes_from_usernames! 
end 

config.to_prepare do 
    User.exclude_routes_from_usernames! 
end 

Pero no estoy seguro de si User es el lugar adecuado para estar examinando Rails.application.routes. Creo que podría hacer lo mismo con el código en lib/pero no estoy seguro si eso es correcto tampoco.

Otra opción es simplemente aplicar la sugerencia de mu en to_prepare. Eso funciona, pero parece que hay un retraso notable en volver a cargar las rutas en cada solicitud en mi entorno de desarrollo, por lo que no estoy seguro de si esta es una buena opción, aunque es SECO, al menos.

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 

Respuesta

22

Puede forzar las rutas para ser cargado antes de mirar Rails.application.routes con esto:

Rails.application.reload_routes! 

Así que trate de esto en su config/application.rb:

config.after_initialize do 
    Rails.application.reload_routes! 
    Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}" 
end 

he hecho cosas similares que necesitaba verificar las rutas (para conflictos con /:slug rutas) y terminé poniendo el reload_routes! y la verificación en un config.after_initialize como lo estás haciendo.

+0

Gran idea! Resulta que en realidad estamos usando esto para la misma cosa (estoy actualizando un 'atributo_categoría' llamado' Usuario.nombres_válidos_inválidos' que se usa como una lista de exclusión con 'validates_exclusion_of'). Creo que todavía necesito el to_prepare para el modo de desarrollo. Sin él, funciona bien en la primera solicitud (ahora que estoy usando tu sugerencia), pero después de eso creo que mi 'User.invalid_usernames = Set.new' lo está golpeando. Parece que solo estás usando after_initialize, así que me pregunto si hay alguna forma inteligente de solucionarlo. – poochenza

+0

Esta respuesta me ayudó mucho, así que la acepto aunque no termine usándola (¡abierta a críticas si crees que debería hacerlo!) Aquí está mi solución completa, me encantaría tu opinión si tienes tiempo: http: //stackoverflow.com/a/8713207/1126857 – poochenza

+0

@poochenza: utilicé 'after_initialize' para asegurarme de que no aparecían nuevos conflictos entre lanzamientos: si agrega una ruta'/pancakes' y publica dos semanas más tarde, desea saber si Al mismo tiempo, alguien creó un usuario de "panqueques" en el sistema de producción. Luego comparo los nuevos nombres de usuario con las rutas a medida que se crean o actualizan los nombres de usuario. –

2

Si usted está tratando de ejecutar código en un inicializador después de las rutas han cargado, puede intentar utilizar la opción after::

initializer "name_of_initializer", after: :add_routing_paths do |app| 
    # do custom logic here 
end 

Usted puede encontrar eventos de inicialización aquí: http://guides.rubyonrails.org/configuring.html#initialization-events

+0

Este inicializador nunca se ejecutará para mí en los carriles 4.1.14.1 – nolith

Cuestiones relacionadas