1

我在我的 Rails 3.1 应用程序中使用了一个自定义的 Rack 中间件,它包裹了一个普通的 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 堆栈在代码更改时需要重新加载这个中间件?

4

3 回答 3

2

您想要的工具是autoload。当 Rails 在 dev 中重新加载时,它会遍历自动加载和明确定义的“可卸载”常量并删除它们(监视堆栈管理这个)。

在插件的主 lib 目录中,例如。lib/stacked_router.rb,如果您声明:

autoload Example::Middleware::StackedRouter, 'lib/middleware/stacked_router'

我认为你应该得到你正在寻找的行为。

请注意,如果您不喜欢自动加载(人们认为它会干扰monkeypatch 的能力),您可以标记一个常量(unloadable,然后 require 文件load(只是使用require不会第二次拾取文件)。或者+ load. 这也会在 prod 中加载每个请求的类,所以可能有条件地加载或需要取决于 env?自动加载可能是更好的选择 IMO。

请注意,我发现实际的 Rails 代码(不是 Rails 文档)是最好的参考。

于 2012-01-26T18:01:32.937 回答
1

看起来 Rails 在服务器启动时正在将 ProductsController 的副本加载到您的中间件中,并保留该缓存副本。我对此不是 100% 确定的,但是当您尝试使用 proc 加载中间件时会发生什么?例如

stacked_router = Proc.new {
  Example::Middleware::StackedRouter.new(ProductsController.action(:show))
}

这应该有望使它在每个请求上加载一个新的中间件(和一个新的 ProductsController)。它可能对生产没有帮助。我面前没有类似的代码,所以我无法对此进行测试。

于 2012-01-23T19:58:00.260 回答
1

如果您正在使用 Pow,您可以使用 powder gem 轻松重启 Pow,而无需执行 touchtmp/restart.txt命令。请参阅https://github.com/Rodreegez/powder

于 2012-01-23T18:26:19.507 回答