加载路由后运行的 Rails 初始值设定项? [英] Rails initializer that runs *after* routes are loaded?
问题描述
我想在 Rails 应用程序启动时设置一个类属性.它需要检查一些路由,因此需要在我的自定义代码运行之前加载这些路由.我很难找到一个可靠的地方来勾搭.
I want to set a class attribute when my Rails app starts up. It requires inspecting some routes, so the routes need to be loaded before my custom code runs. I am having trouble finding a reliable place to hook in.
这在测试"环境中非常有效:
This works PERFECTLY in the "test" environment:
config.after_initialize do
Rails.logger.info "#{Rails.application.routes.routes.map(&:path)}"
end
但它在开发"环境中不起作用(路由是空的)
But it doesn't work in the "development" environment (the routes are empty)
现在,我似乎通过在 config.to_prepare
中运行相同的代码来使事情在开发模式下工作,我知道这发生在每个请求之前.不幸的是,单独使用 to_prepare
似乎在测试模式下不起作用,因此会出现重复.
For now I seem to have things working in development mode by running the same code in config.to_prepare
which I understand happens before every request. Unfortunately using to_prepare
alone doesn't seem to work in test mode, hence the duplication.
我很好奇为什么在测试模式下在 after_initialize 之前加载路由,而不是在开发模式下.真的,什么是最好的钩子?是否有一个适用于所有环境的钩子?
I'm curious why the routes are loaded before after_initialize in test mode, but not in development mode. And really, what is the best hook for this? Is there a single hook that will work for all environments?
*编辑*
*EDIT*
mu 重新加载路线的建议很棒.它使我能够在所有环境中一致访问 after_initialize 中的路由.不过对于我的用例,我认为我仍然需要从 to_prepare 运行代码,因为我在模型上设置了一个类属性,并且在每次请求之前重新加载模型.
mu's suggestion of reloading the routes was great. It gave me consistent access to the routes within after_initialize in all environments. For my use case though, I think I still need to run the code from to_prepare as well, since I'm setting a class attribute on a model and the models are reloaded before each request.
这就是我最终做的事情.
So here's what I ended up doing.
[:after_initialize, :to_prepare].each do |hook|
config.send(hook) do
User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("
").scan(/s/(w+)/).flatten.compact.uniq
end
end
我觉得有点乱.我想我宁愿做这样的事情:
It seems a bit messy to me. I think I'd rather do something like:
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/中的代码做同样的事情,但我不确定这是否正确.
But I'm not sure if User
is the right place to be examining Rails.application.routes
. I guess I could do the same thing with code in lib/ but I'm not sure if that's right either.
另一种选择是在 to_prepare 上应用 mu 的建议.这有效,但在我的开发环境中重新加载每个请求的路由似乎有明显的延迟,所以我不确定这是否是一个好的调用,尽管它至少是 DRY 的.
Another option is to just apply mu's suggestion on to_prepare. That works but there seems to be a noticeable delay reloading the routes on every request in my dev environment, so I'm not sure if this is a good call, although it's DRY, at least.
config.to_prepare do
Rails.application.reload_routes!
User.invalid_usernames += Rails.application.routes.routes.map(&:path).join("
").scan(/s/(w+)/).flatten.compact.uniq
end
推荐答案
你可以在查看 Rails.application.routes
之前强制加载路由:
You can force the routes to be loaded before looking at Rails.application.routes
with this:
Rails.application.reload_routes!
所以在你的 config/application.rb
中试试这个:
So try this in your 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
就像你在做的那样.
I've done similar things that needed to check the routes (for conflicts with /:slug
routes) and I ended up putting the reload_routes!
and the checking in a config.after_initialize
like you're doing.
这篇关于加载路由后运行的 Rails 初始值设定项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!