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

问题描述 投票:269回答:12

由于最新的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);
ruby-on-rails class module autoload ruby-on-rails-3
12个回答
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)

2
投票

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

请检查这个GitHub Discussion Link


1
投票

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

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

0
投票

正确拼写文件名。

认真。我和一个班级争斗了一个小时,因为这个类是Governance :: ArchitectureBoard,文件在lib / governance / architecture_baord.rb中(在“board”中转换为O和A)

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


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。请注意,这不适用于生产环境,因为永久重新加载会降低计算机的速度。


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",它的工作方式相同。

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


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

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


41
投票

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

  • config.autoload_paths”方法:仅在您加载仅在一个地方定义的类时才有效。如果已经在其他地方定义了某个类,则无法通过此方法再次加载它。
  • config/initializer/load_rb_file.rb”方法:永远有效!无论目标类是新类还是现有类的“开放类”或“猴子补丁”,它始终有效!

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


28
投票

非常相似,但我觉得这更优雅一点:

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

14
投票

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

在application.rb中......

require '/lib/this_file.rb' 

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

require './lib/this_file.rb' 

和rails完美地加载文件。

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


7
投票

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

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

5
投票

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

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

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 

4
投票

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

require 'mymodule'

在model.rb文件的顶部。

© www.soinside.com 2019 - 2024. All rights reserved.