在Rails 3中从lib文件夹加载模块/类的最佳方法?

时间:2010-07-28 19:36:05

标签: ruby-on-rails class module autoload ruby-on-rails-3

由于最新的Rails 3版本不再自动加载lib中的模块和类, 什么是加载它们的最佳方式?

来自github:

A few changes were done in this commit:

Do not autoload code in *lib* for applications (now you need to explicitly 
require them). This makes an application behave closer to an engine 
(code in lib is still autoloaded for plugins);

12 个答案:

答案 0 :(得分:248)

As of Rails 2.3.9config/application.rb中有一个设置,您可以在其中指定包含要自动加载的文件的目录。

来自application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)

答案 1 :(得分:196)

# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

来源:Rails 3 Quicktip: Autoload lib directory including all subdirectories, avoid lazy loading

请注意,lib文件夹中包含的文件仅在服务器启动时加载。如果您想要舒适地自动加载这些文件,请阅读:Rails 3 Quicktip: Auto reload lib folders in development mode。请注意,这不适用于生产环境,因为永久重新加载会降低计算机速度。

答案 2 :(得分:81)

自动加载内容的神奇之处

我认为控制自动加载内容的文件夹的选项已经在其他答案中得到了充分的介绍。但是,如果其他人遇到麻烦,虽然他们已根据需要修改了自动加载路径,但这个答案试图解释这个自动加载的背后的魔力是什么。

因此,当涉及从子目录加载东西时,你应该知道一个问题或一个约定。有时Ruby / Rails魔术(这次主要是Rails)可能会让人难以理解为什么会发生什么。仅当模块名称对应于父目录名称时,才会加载在自动加载路径中声明的任何模块。因此,如果你试图加入lib/my_stuff/bar.rb之类的东西:

module Foo
  class Bar
  end
end

它不会自动加载。如果您将父目录重命名为foo,那么再次将您的模块托管在路径lib/foo/bar.rb。它会在你身边。另一个选项是按模块名称命名要自动加载的文件。显然,那个名称只能有一个文件。如果你需要将你的东西拆分成许多文件,你当然可以使用那个文件来要求其他文件,但我不建议这样做,因为当你在开发模式下修改那些其他文件时,Rails就无法自动生成为你重新加载它们。但是,如果您真的希望您可以通过模块名称拥有一个文件,然后指定使用该模块所需的实际文件。所以你可以有两个文件:lib/my_stuff/bar.rblib/my_stuff/foo.rb,前者与上面相同,而后者包含一行:require "bar",这样就可以了。

P.S。我觉得有必要增加一件更重要的事情。最近,每当我想在lib目录中有需要自动加载的东西时,我倾向于开始认为如果这是我实际上专门为这个项目开发的东西(它通常是,它可能有一天变成许多项目或git子模块等中使用的“静态”代码片段。在这种情况下它肯定应该在lib文件夹中)然后它的位置可能根本不在lib文件夹中。也许它应该在app文件夹下的子文件夹中·我有一种感觉,这是新的rails方式。显然,无论你在自动加载路径中放置什么东西,同样的魔法都在工作中,所以对这些东西都有好处。无论如何,这只是我对这个问题的看法。你可以自由地不同意。 :)


更新:关于魔法的类型..

正如severin在他的评论中指出的那样,核心“自动加载模块机制”肯定是Ruby的一部分,但自动加载路径的东西不是。您不需要Rails来autoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar")。当你第一次尝试引用模块Foo时,它会为你加载。然而,Rails所做的是它为我们提供了一种从注册文件夹中自动尝试和加载内容的方法,并且这种方式已经实现,它需要假设一些有关命名约定的内容。如果没有这样实现,那么每次引用当前未加载的内容时,都必须遍历所有自动加载文件夹中的所有文件,并检查它们中是否包含您尝试引用的内容。这反过来会破坏自动加载和自动加载的想法。但是,有了这些约定,它可以从模块/类中扣除您尝试加载可能定义的位置并加载它。

答案 3 :(得分:41)

警告:如果你想从'lib'文件夹中加载'monkey patch'或'open class',请不要使用'autoload' approach

  • config.autoload_paths”方法:仅在加载仅在一个地方定义的类时才有效。如果某个类已经在其他地方定义了,那么你就不能通过这种方法再次加载它。

  • config/initializer/load_rb_file.rb”方法:始终有效!无论目标类是新类还是现有类的“开放类”或“猴子补丁”,它始终有效!

有关详细信息,请参阅:https://stackoverflow.com/a/6797707/445908

答案 4 :(得分:28)

非常相似,但我认为这更优雅:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]

答案 5 :(得分:14)

在我的情况下,我试图直接在lib目录下加载文件。

在application.rb ...

require '/lib/this_file.rb' 

即使在控制台中也没有工作,然后当我尝试

require './lib/this_file.rb' 

和rails完美加载文件。

我还是漂亮的菜鸟,我不确定为什么会这样,但它确实有效。如果有人想向我解释,我会很感激:D我希望这可以帮助某人。

答案 6 :(得分:7)

我遇到了同样的问题。这是我如何解决它。该解决方案加载lib目录和所有子目录(不仅是直接)。当然,您可以将它用于所有目录。

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

答案 7 :(得分:5)

config.autoload_paths对我不起作用。我以其他方式解决它

  

Ruby on rails 3不会从/ lib文件夹自动重新加载(自动加载)代码。我通过放入ApplicationController

来解决它
Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 

答案 8 :(得分:4)

如果只有某些文件需要访问lib中的模块,只需在需要它的文件中添加一个require语句即可。例如,如果一个模型需要访问一个模块,请添加:

require 'mymodule'

位于model.rb文件的顶部。

答案 9 :(得分:2)

Rails 5开始,建议将lib文件夹放在app目录下,或者为servicespresentersfeatures创建文件夹的其他有意义的名称空间。等,并将其放在app目录下,以便通过rails自动加载。

请同时查看此GitHub Discussion Link

答案 10 :(得分:1)

有几个原因导致从lib加载时出现问题 - 有关详细信息,请参阅此处 - http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/

  • 修复自动加载路径
  • 线程安全相关
  • 命名相关
  • ...

答案 11 :(得分:0)

正确拼写文件名。

严重。我和一个班级争斗了一个小时,因为这个班级是Governance :: ArchitectureBoard,文件在lib / governance / architecture_baord.rb中(在&#34中转换为O和A;董事会")

回想起来似乎很明显,但是跟踪的是恶魔。如果在Rails期望它的文件中没有定义类,那么基于修改类名,它根本就不会找到它。