Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 重新加载rails中间件而不重新启动开发中的服务器_Ruby On Rails_Ruby On Rails 4_Rack_Rack Middleware - Fatal编程技术网

Ruby on rails 重新加载rails中间件而不重新启动开发中的服务器

Ruby on rails 重新加载rails中间件而不重新启动开发中的服务器,ruby-on-rails,ruby-on-rails-4,rack,rack-middleware,Ruby On Rails,Ruby On Rails 4,Rack,Rack Middleware,我有一个rails 4应用程序,其中间件位于lib/some/middleware.rb,当前通过如下初始化器注入堆栈: MyApp::Application.configure.do |config| config.middleware.use 'Some::Middleware' end 不幸的是,每当我更改某些内容时,我都需要重新启动服务器。在开发模式下,如何在每个请求上重新加载它?我见过类似的问题,关于在to_prepare块中使用自动加载或包装代码来重新加载lib代码,但我不

我有一个rails 4应用程序,其中间件位于lib/some/middleware.rb,当前通过如下初始化器注入堆栈:

MyApp::Application.configure.do |config|
    config.middleware.use 'Some::Middleware'
end
不幸的是,每当我更改某些内容时,我都需要重新启动服务器。在开发模式下,如何在每个请求上重新加载它?我见过类似的问题,关于在to_prepare块中使用自动加载或包装代码来重新加载lib代码,但我不确定如何在这种情况下应用

谢谢, -FJM

更新#1


如果我尝试删除中间件,然后将其重新添加到to_prepare块中,我会得到一个错误“无法修改冻结的数组”。

您不能简单地使用它吗?如果我理解您的问题,那么您希望确保环境重新加载您对代码所做的每一次更改。这就是shotgun将要做的。

我认为Rails在某种程度上足够聪明,可以在运行时替换中间件代码,但我可能错了

下面是我的想法,绕过Ruby类加载的疯狂,利用Rails类重新加载

将中间件添加到堆栈中:

# config/environments/development.rb
[...]
config.middleware.use "SomeMiddleware", "some_additional_paramter"
使用自动重新加载,但确保正在运行的rails实例和已初始化的中间件对象“忘记”执行的实际代码:

# app/middlewares/some_middleware.rb
class SomeMiddleware
  def initialize(*args)
    @args = args
  end

  def call(env)
    "#{self.class}::Logic".constantize.new(*@args).call(env)
  end

  class Logic
    def initialize(app, additional)
      @app        = app
      @additional = additional
    end

    def call(env)
      [magic]
      @app.call(env)
    end
  end
end
逻辑上的变化应该通过rails在每次请求时自动重新加载来获取


我认为这实际上可能会成为一块有用的宝石

基于@phoet的答案,我们实际上可以用这种延迟加载来包装任何中间件,我发现这更有用:

class ReloadableMiddleware
  def initialize(app, middleware_module_name, *middleware_args)
    @app = app
    @name = middleware_module_name
    @args = middleware_args
  end

  def call(env)
    # Lazily initialize the middleware item and call it immediately
    @name.constantize.new(@app, *@args).call(env)
  end
end
然后可以将它连接到Rails配置中,任何其他中间件作为其第一个参数,以字符串形式给出:

Rails.application.config.middleware.use ReloadableMiddleware, 'YourMiddleware'
或者-我将其打包到一个名为
可重新加载的\u中间件
的gem中,可以这样使用:

Rails.application.config.middleware.use ReloadableMiddleware.wrap(YourMiddleware)

在带有新的默认Zeitwork代码加载器的Rails 6中,这对我来说很有用:

# at the top of config/application.rb, after Bundler.require    

# Load the middleware. It will later be hot-reloaded in config.to_prepare
Dir["./app/middleware/*.rb"].each do |middleware|
  load middleware
end
在其下方配置
类应用程序的部分
,在
配置中添加热重新加载以准备

middleware = "#{Rails.root}/app/middleware"
Rails.autoloaders.main.ignore(middleware)

# Run before every request in development mode, or before the first request in production
config.to_prepare do
  Dir.glob("#{middleware}/*.rb").each do |middleware|
    load middleware
  end
end

我查看了一下猎枪,但它似乎在每一个请求上都重新装填了所有东西,这让我觉得对我的需求来说是可怕的过度。我想以某种方式卸载和重新加载我的Some::Middleware类,就像我的模型/控制器一样。从概念上讲,这太过分了。但在开发环境中,我发现它在实际实践中非常优秀。自从我开始使用它以来,它从未明显影响性能或引入任何意外问题。但从美学的角度来看,它确实很难看。请将您的中间件放入
app/middleware
,然后再试一次。将字符串添加到中间件堆栈而不是类本身时,使用字符串也很重要,因为它不会被重新加载。@phoet我尝试了你的建议,但没有成功。这太神奇了。恒定化是什么导致它重新加载的?我认为rails正确地重新加载了代码,但是由于中间件是在初始化期间加载的,因此您必须确保代码在每次请求时都会得到重新评估。如果您坚持使用真正的类调用
.new
,它将有问题,因为重新加载,现在在对象树中有两个
逻辑
类。那不好。所以,这就是为什么你必须将逻辑传递给另一个类,同时也不要保持对类的引用不变。@FrankJosephmatia我创建了一个drop-in gem的alpha版本,它应该负责开发中的重新加载:看起来不错。最后,我将您最初的建议包装到一个mixin中,并将其包含在我的中间件类中。不过我得试一下。谢谢你,这是金色的!