我在Rails 3.1应用程序中使用自定义Rack中间件,它包裹着一个vanilla Rails控制器:
routes.rb
中的
stacked_router =
Example::Middleware::StackedRouter.new(ProductsController.action(:show))
match '/:id', :to => stacked_router
example/middleware/stacked_router.rb
中的
class Example::Middleware::StackedRouter
def initialize(app)
@app = app
end
def call(env)
# ... do stuff before forwarding the request, then
@app.call(env) # forward the request
end
end
这很好用。
但是有一个问题:当我现在更改ProductsController
中的代码时,更改不会自动获取。我必须手动重启应用程序(touch tmp/restart.txt
)
告诉Rails堆栈,只要代码被更改,它需要重新加载这个中间件的方法是什么?
答案 0 :(得分:2)
您想要的工具是autoload。当Rails在dev中重新加载时,它会迭代自动加载并显式定义'unloadable'常量并删除它们(watch stack管理它)。
在插件的主lib目录中,例如。 lib/stacked_router.rb
,如果您声明:
autoload Example::Middleware::StackedRouter, 'lib/middleware/stacked_router'
我认为应该获得您正在寻找的行为。
请注意,如果您不喜欢自动加载(人们认为它会影响monkeypatch的功能),您可以标记一个常量(unloadable,然后要求文件load
(仅使用{ {1}}第二次不会提取文件。
或+ require
。这也会在prod中的每个请求中加载类,所以可能有条件地加载或需要取决于env?自动加载可能是IMO的更好选择。
请注意,我发现actual Rails code(不是Rails文档)是最佳参考。
答案 1 :(得分:1)
如果您使用Pow,您可以使用粉末宝石轻松重启Pow,而无需执行touch tmp/restart.txt
命令。请参阅https://github.com/Rodreegez/powder。
答案 2 :(得分:1)
看起来Rails正在将服务器启动到中间件时加载ProductsController的副本,并保留该缓存副本。我不是100%肯定这一点,但是当你尝试用proc加载中间件时会发生什么? e.g。
stacked_router = Proc.new {
Example::Middleware::StackedRouter.new(ProductsController.action(:show))
}
这应该有希望使它在每个请求上加载一个新的中间件(和一个新的ProductsController)。它可能对生产没有帮助。我面前没有类似的代码,所以我无法测试。