Je souhaite définir un attribut de classe lorsque mon application Rails démarre. Cela nécessite d'inspecter certaines routes, donc les routes doivent être chargées avant l'exécution de mon code personnalisé. Je ne parviens pas à trouver un endroit fiable pour accrocher dansInitialiseur Rails qui exécute * après * les routes sont chargées?
Cela fonctionne parfaitement dans l'environnement « test »:.
config.after_initialize do
Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}"
end
Mais il ne le fait pas travail dans l'environnement « développement » (les routes sont vides)
Pour l'instant je semble avoir des choses fonctionnant en mode de développement en exécutant le même code dans config.to_prepare
qui je crois arrive avant chaque demande. Malheureusement, en utilisant to_prepare
seul ne semble pas fonctionner en mode test, d'où la duplication.
Je suis curieux de savoir pourquoi les routes sont chargées avant after_initialize en mode test, mais pas en mode développement. Et vraiment, quel est le meilleur crochet pour cela? Y a-t-il un seul crochet qui fonctionnera pour tous les environnements?
* EDIT *
suggestion de mu de rechargement des routes était super. Cela m'a donné un accès cohérent aux routes dans after_initialize dans tous les environnements. Pour mon cas d'utilisation cependant, je pense que je dois encore exécuter le code de to_prepare, puisque je mets un attribut de classe sur un modèle et que les modèles sont rechargés avant chaque requête.
Alors voici ce que j'ai fini par faire.
[: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
Cela me semble un peu compliqué. Je pense que je préfère faire quelque chose comme:
config.after_initialize do
User.exclude_routes_from_usernames!
end
config.to_prepare do
User.exclude_routes_from_usernames!
end
Mais je ne sais pas si User
est le bon endroit pour être examiner Rails.application.routes
. Je suppose que je pourrais faire la même chose avec du code dans lib/mais je ne suis pas sûr que ce soit correct non plus.
Une autre option consiste à appliquer simplement la suggestion de mu sur to_prepare. Cela fonctionne mais il semble y avoir un retard notable recharger les routes sur chaque demande dans mon environnement de développement, donc je ne suis pas sûr si c'est un bon appel, même si c'est sec, au moins.
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
Excellente idée! Il s'avère que nous l'utilisons pour la même chose (je mets à jour un 'class_attribute' appelé' User.invalid_usernames' qui est utilisé comme liste d'exclusion avec 'validates_exclusion_of'). Je pense que j'ai encore besoin du to_prepare pour le mode développement. Sans cela, cela fonctionne bien sur la première requête (maintenant que j'utilise votre suggestion), mais après cela, je pense que mon 'User.invalid_usernames = Set.new' l'écrase. Il semble que vous n'utilisiez que after_initialize, donc je me demande s'il y a une façon intelligente de contourner cela? – poochenza
Cette réponse m'a beaucoup aidé alors je l'accepte même si je n'ai pas fini par l'utiliser (ouvert à la critique si vous pensez que je devrais bien!) Voici ma solution complète, aimerais vos commentaires si vous avez le temps: http: //stackoverflow.com/a/8713207/1126857 – poochenza
@poochenza: J'ai utilisé 'after_initialize' pour m'assurer qu'aucun nouveau conflit n'est apparu entre les versions: si vous ajoutez une route'/pancakes' et publiez deux semaines plus tard, vous voulez savoir si Quelqu'un a créé un utilisateur de "crêpes" sur le système de production en même temps. Ensuite, je compare les nouveaux noms d'utilisateur par rapport aux itinéraires lorsque les noms d'utilisateur sont créés ou mis à jour. –