【问题标题】:Why does code need to be reloaded in Rails 3?为什么需要在 Rails 3 中重新加载代码?
【发布时间】:2011-07-15 14:29:15
【问题描述】:

我是一名前 PHP 开发人员,学习 Rails 和 Sinatra。在 PHP 中,每个页面请求都会加载所有必需的文件。如果我更改了一些代码并刷新了页面,我可以确定代码是新鲜的。

在 Rails 3 中,控制器代码在每次请求时都是新鲜的。但是,如果我修改 /lib 文件夹中的任何代码,我需要重新启动服务器才能使更改生效。

为什么会这样?这与 Ruby 的设计方式有关吗? Rails 是否进行了一些优化以避免在每个请求上重新加载代码?

谢谢!

编辑:我最感兴趣的是引擎盖下发生的事情。像 Rails 和 Sinatra 这样的框架会为类做一些特殊的缓存吗?如果是这样,他们会做什么? Ruby 中的默认行为是在每次请求时重新加载所有代码吗?为什么我们需要 Shotgun for Sinatra (http://sinatra-book.gittr.com/#automatic_code_reloading) 之类的工具?

【问题讨论】:

  • 我还没有看到这个问题。也许您正在更改的代码仅在 Rails 启动时加载(例如配置参数)

标签: ruby-on-rails ruby caching sinatra


【解决方案1】:

当您处于开发模式时,您应该告诉 Rails 不要缓存您的类,以便它们每次都重新加载。这意味着每个请求类基本上都在 rails 解释器中重新定义。 Rails.root/config/environments/development.rb 中的设置:

config.cache_classes = false

lib/ 目录中的类通常通过初始化程序加载,不受此设置的约束。

当您迁移到生产环境时,您会希望缓存所有类,以便请求更快,并且 Rails 将对模型上的范围等内容进行优化。

您可以在另一个初始化程序(可能称为 Rails.root/config/initializers/development_reload.rb)中放入一些东西,该初始化程序会在开发中的每个请求(或只是您正在处理的请求)重新加载 lib 目录:

# file development_reload.rb
if Rails.env.development?
  ActionDispatch::Callbacks.after do
    load 'filename_in_lib'
    # or
    Dir.entries("#{Rails.root}/lib").each do |entry|
      load entry if entry =~ /.rb$/
    end
  end
end

我正在调用“load”,因此它实际上会重新加载文件,而“require”只会检查它是否已加载并确定它已经加载,因此它不会重新加载它。 (我只是把它放在一起并没有使用它,但是 Ruby 非常灵活,可以让你做很多事情。)明智地使用这样的东西,并且只在开发环境中。

为什么需要在 Rails 3 中重新加载代码?

Ruby 是一种解释型语言(JRuby 对预编译有一些支持,但它仍然是解释型的)。在初始化时解释类的定义类似于编译 php 并以可执行格式部署(有点)。解释器不会一直为重新定义类而烦恼。

强制显式重新加载是对这种类型的解释语言的优化。 (如果您在 php 中进行 AOT 编译,您还需要在更改后重新加载已编译的“字节码”;默认 php 使用动态编译,这是您正在利用的)

【讨论】:

  • 谢谢!这对解决我的挫败感很有帮助,但这不是我想要的答案。我想知道为什么必须重新加载代码。在 PHP 中我不必担心这个。
  • 太棒了,说得通。也许您应该将该响应放在答案的正文中?
  • 谢谢布兰登!我必须使用不同的回调来让我的重新加载发生一个 gem (ActiveAdmin) 部分重新加载我的模型:ActionDispatch::Callbacks.to_prepare do {}apidock.com/rails/ActionDispatch/Callbacks/to_prepare/class
  • @VenkatD。 PHP 在每个请求上都会崩溃
【解决方案2】:

更高级的方法怎么样:

    ActionDispatch::Reloader.cleanup!
    ActionDispatch::Reloader.prepare!

这取自 Rails/ActiveRecord v3.2.13 - active_record/railtie.rb

加载方法对我不起作用。仅仅执行加载会导致一个奇怪的问题,它会触发某些验证器两次。

为了解决这个问题,我在重新加载 User 之前尝试了 Object.send(:remove_const, User),但后来我失去了对该类的观察者,所以我开始追尾。

上述方法会重新加载所有类,因此也许还有更好的方法可以从缓存中正确删除单个类并重新加载它...

【讨论】:

  • 我们应该在哪里设置这些设置?
猜你喜欢
  • 2015-02-07
  • 2015-10-29
  • 1970-01-01
  • 2014-04-30
  • 2011-08-02
  • 2017-02-24
  • 2012-12-15
  • 2017-06-22
  • 2020-05-03
相关资源
最近更新 更多