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

5
我是一名曾经的PHP开发者,现在正在学习Rails和Sinatra。在PHP中,每个页面请求都会加载所有必需的文件。如果我更改了一些代码并刷新页面,我可以确定代码是最新的。
在Rails 3中,每次请求控制器代码都是最新的。但是,如果我修改/lib文件夹中的任何代码,则需要重新启动服务器才能使更改生效。
为什么会这样?这与Ruby的设计有关吗?Rails是否进行了一些优化以避免在每个请求上重新加载代码?
谢谢!
编辑:我主要对底层发生的事情感兴趣。像Rails和Sinatra这样的框架是否会为类执行某些特殊缓存?如果是这样,它们会做什么?默认行为在Ruby中是所有代码在每个请求上重新加载吗?为什么我们需要像Sinatra的Shotgun工具(http://sinatra-book.gittr.com/#automatic_code_reloading)这样的工具?

我没有遇到过那个问题。也许你正在更改的代码是仅在Rails启动时加载的某些内容(例如配置参数)。 - Zabba
2个回答

20

在开发模式下,您应该告诉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中,我不必担心这个问题。 - Venkat D.
太棒了,那很有道理。也许你应该把这个回答放在正文中? - Venkat D.
谢谢Brandon!我不得不使用不同的回调来让我的重新加载发生在gem(ActiveAdmin)部分重新加载我的模型之后:ActionDispatch :: Callbacks.to_prepare do {}http://apidock.com/rails/ActionDispatch/Callbacks/to_prepare/class - Gabe Kopley
1
@VenkatD。PHP在每个请求时都会拆除。 - Carson Reinke

2

可以采用更高层次的方法:

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

这是从Rails / ActiveRecord v3.2.13 - active_record/railtie.rb中提取的。
对我来说,加载方法不起作用。只是执行load会导致某些验证器触发两次。
为了解决这个问题,我尝试在重新加载User之前使用Object.send(:remove_const, User),但然后我失去了该类上的观察者,所以我开始追逐自己的尾巴。
上述方法重新加载所有类,因此可能仍然有更好的方法来正确地从缓存中删除单个类并重新加载它...

我们应该在哪里设置这些设置? - Radhakrishna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接