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


273

由于最新的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);

Answers:



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

来源:Rails 3快速提示:自动加载包括所有子目录的lib目录,避免延迟加载

请注意,仅在服务器启动时才加载lib文件夹中包含的文件。如果您希望自动重新加载这些文件,请阅读:Rails 3快速提示:在开发模式下自动重新加载lib文件夹。请注意,这并不适合生产环境,因为永久性重新加载会降低机器的速度。


链接已死
Besi

84

自动加载东西的魔力

我认为其他答案已经充分介绍了控制从中完成自动加载的文件夹的选项。但是,如果有人根据需要修改了自动加载路径后却加载了麻烦的东西,那么此答案将试图解释自动加载背后的魔力是什么。

因此,从子目录加载内容时,您应该知道一个陷阱或约定。有时,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所做的是,它为我们提供了一种尝试从注册的文件夹中自动加载内容的方法,并且这种实现方式需要假设一些有关命名约定的方式。如果尚未实现,则每次引用当前未加载的内容时,都必须遍历所有自动加载文件夹中的所有文件,并检查其中是否包含您要引用的内容。这反过来会破坏自动加载和自动重新加载的想法。但是,有了这些约定,它可以从模块/类中扣除您尝试加载的位置(可能定义的位置)并只是加载它。


1
为什么这红宝石魔术?Ruby只是提供了Module#autoload函数,您可以在访问(未定义的)常量时命令使用该函数来加载要加载的文件(请参阅ruby-doc.org/core-1.9.3/Module.html#method-i-autoload)。我认为模块/类名称与目录/文件的匹配是在Rails / ActiveSupport中完成的(例如,在这里:github.com/rails/rails/blob/…)。我错了吗?
Severin 2012年

是的,我相信你是正确的。当Zabba指出其“缺陷”时,我太匆忙而无法“纠正”我的原始答案。让我再更新一点答案来澄清这个问题。
蒂莫(Timo)2012年

1
我花了一个半小时左右的时间。我需要(想要)自动加载Sprockets :: JSRender :: Processor。可以通过进入Rails控制台并执行“ Sprockets :: JSRender :: Processor”。下划线并消除它是“ sprockets / js_render / processor”(添加了.rb)的方式找到该路径。
pedz

你刚刚救了我的理智。〜松了一口气〜非常感谢您的分享:)
Brenden

感谢您提供的最有用的评论。在我阅读您的评论之前,我不理解为什么某些模块会表现出与以前一样的状态。祝福你!
mjnissim

41

警告:如果您想从“ lib”文件夹中加载“ monkey patch”或“ open class”,请不要使用“ autoload”方法

  • config.autoload_paths ”方法:仅在加载仅在一个位置定义的类时有效。如果已经在其他地方定义了某个类,则无法通过这种方法再次加载它。

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

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


6
这是要理解的关键区别。谢谢你
Tyler Collier 2013年


18

就我而言,我试图直接在lib目录下直接加载文件。

在application.rb中...

require '/lib/this_file.rb' 

即使在控制台中也无法正常工作,然后当我尝试

require './lib/this_file.rb' 

Rails会完美加载文件。

我仍然还是个菜鸟,我不确定为什么会这样,但是它能正常工作。如果有人想向我解释一下,我将不胜感激:DI希望这对任何人都可以有所帮助。


2
这是因为./lib/this_file.rb在当前目录中查找(在Rails控制台中,这将是您的Rails根目录),而/lib/this_file.rb将其查找为绝对路径。例如:./ lib / this_file.rb = /var/www/myrailsapp/lib/this_file.rb,/lib/this_file.rb = /lib/this_file.rb
Jason

7

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

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

5
这完全破坏了Rails的命名空间惯例的讨厌的副作用。如果在自动加载查找中,定义Bar :: Foo的lib / bar / foo.rb出现在定义Foo的lib / foo.rb之前,那么您将得到令人困惑的错误,例如Expected lib/bar/foo.rb to define constant Foo如果尝试通过引用Foo加载lib / foo.rb不变。
2013年

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文件的顶部。


50
您不应该require在Rails应用程序中使用它,因为它会阻止ActiveSupport::Dependencies适当地[卸载]该代码。相反,您应该使用config.autoload_paths上述答案,然后根据需要添加/扩展。
ben_h 2010年

13
谢谢@Mike,我要去做您所做的事情,很高兴看到为什么不好的解释,谢谢您不要删除答案。
pupeno 2011年

如果只想加载一个模块,那么包含“ mymodule”呢?
迈克,

1
@ben_h您是否应该不在requireRails应用程序中的任何位置?在rake任务中,我当前正在require和- include驻留在其中的模块lib/。我不应该那样做吗?
丹尼斯

@ben_h我的搜索显示它对于require您的lib/代码是常见的(例如,此博客文章此SO答案)。我仍然不确定整个事情。您可以在不使用索赔的背后提供更多证据require吗?
丹尼斯

2

正确拼写文件名。

说真的 我与一个班级竞争了一个小时,因为该班级是Governance :: ArchitectureBoard,并且文件位于lib / governance / architecture_baord.rb中(“ board”中的O和A换位了)

回想起来似乎很明显,但这是魔鬼追踪的结果。如果该类未在Rails期望基于修改类名的文件中定义,则根本不会找到它。



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.