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

发布于 2024-09-11 16:01:30 字数 216 浏览 1 评论 0原文

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

来自github:

此提交中进行了一些更改:

不要在应用程序的 *lib* 中自动加载代码(现在您需要显式地 
需要它们)。这使得应用程序的行为更接近引擎 
(lib 中的代码仍然会自动加载插件);

Since the latest Rails 3 release is not auto-loading modules and classes from lib anymore,
what would be the best way to load them?

From 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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

不交电费瞎发啥光 2024-09-18 16:01:30

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

从应用程序.rb:

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

As of Rails 2.3.9, there is a setting in config/application.rb in which you can specify directories that contain files you want autoloaded.

From application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
兰花执着 2024-09-18 16:01:30
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

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

请注意,lib 文件夹中包含的文件仅在服务器启动时加载。如果您想轻松地自动重新加载这些文件,请阅读:Rails 3 快速提示:在开发模式下自动重新加载 lib 文件夹。请注意,这不适用于生产环境,因为永久重新加载会减慢机器速度。

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

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

Please mind that files contained in the lib folder are only loaded when the server is started. If you want the comfort to autoreload those files, read: Rails 3 Quicktip: Auto reload lib folders in development mode. Be aware that this is not meant for a production environment since the permanent reload slows down the machine.

零度° 2024-09-18 16:01:30

自动加载内容的魔力

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

因此,当涉及到从子目录加载内容时,您应该注意一个陷阱或约定。有时,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,前者与上面相同,后者包含一个line: require "bar" 效果是一样的。

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


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

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

The magic of autoloading stuff

I think the option controlling the folders from which autoloading stuff gets done has been sufficiently covered in other answers. However, in case someone else is having trouble stuff loaded though they've had their autoload paths modified as required, then this answer tries to explain what is the magic behind this autoload thing.

So when it comes to loading stuff from subdirectories there's a gotcha or a convention you should be aware. Sometimes the Ruby/Rails magic (this time mostly Rails) can make it difficult to understand why something is happening. Any module declared in the autoload paths will only be loaded if the module name corresponds to the parent directory name. So in case you try to put into lib/my_stuff/bar.rb something like:

module Foo
  class Bar
  end
end

It will not be loaded automagically. Then again if you rename the parent dir to foo thus hosting your module at path: lib/foo/bar.rb. It will be there for you. Another option is to name the file you want autoloaded by the module name. Obviously there can only be one file by that name then. In case you need to split your stuff into many files you could of course use that one file to require other files, but I don't recommend that, because then when on development mode and you modify those other files then Rails is unable to automagically reload them for you. But if you really want you could have one file by the module name that then specifies the actual files required to use the module. So you could have two files: lib/my_stuff/bar.rb and lib/my_stuff/foo.rb and the former being the same as above and the latter containing a single line: require "bar" and that would work just the same.

P.S. I feel compelled to add one more important thing. As of lately, whenever I want to have something in the lib directory that needs to get autoloaded, I tend to start thinking that if this is something that I'm actually developing specifically for this project (which it usually is, it might some day turn into a "static" snippet of code used in many projects or a git submodule, etc.. in which case it definitely should be in the lib folder) then perhaps its place is not in the lib folder at all. Perhaps it should be in a subfolder under the app folder· I have a feeling that this is the new rails way of doing things. Obviously, the same magic is in work wherever in you autoload paths you put your stuff in so it's good to these things. Anyway, this is just my thoughts on the subject. You are free to disagree. :)


UPDATE: About the type of magic..

As severin pointed out in his comment, the core "autoload a module mechanism" sure is part of Ruby, but the autoload paths stuff isn't. You don't need Rails to do autoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). And when you would try to reference the module Foo for the first time then it would be loaded for you. However what Rails does is it gives us a way to try and load stuff automagically from registered folders and this has been implemented in such a way that it needs to assume something about the naming conventions. If it had not been implemented like that, then every time you reference something that's not currently loaded it would have to go through all of the files in all of the autoload folders and check if any of them contains what you were trying to reference. This in turn would defeat the idea of autoloading and autoreloading. However, with these conventions in place it can deduct from the module/class your trying to load where that might be defined and just load that.

毁梦 2024-09-18 16:01:30

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

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

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

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

Warning: if you want to load the 'monkey patch' or 'open class' from your 'lib' folder, don't use the 'autoload' approach!!!

  • "config.autoload_paths" approach: only works if you are loading a class that defined only in ONE place. If some class has been already defined somewhere else, then you can't load it again by this approach.

  • "config/initializer/load_rb_file.rb" approach: always works! whatever the target class is a new class or an "open class" or "monkey patch" for existing class, it always works!

For more details , see: https://stackoverflow.com/a/6797707/445908

清风无影 2024-09-18 16:01:30

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

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

Very similar, but I think this is a little more elegant:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
南汐寒笙箫 2024-09-18 16:01:30

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

在 application.rb... 中

require '/lib/this_file.rb' 

不起作用,即使在控制台中也是如此,然后当我尝试时

require './lib/this_file.rb' 

,rails 完美加载了文件。

我仍然很菜鸟,我不确定为什么这有效,但它有效。如果有人愿意向我解释,我将不胜感激:希望这对某人有帮助。

In my case I was trying to simply load a file directly under the lib dir.

Within application.rb...

require '/lib/this_file.rb' 

wasn't working, even in console and then when I tried

require './lib/this_file.rb' 

and rails loads the file perfectly.

I'm still pretty noob and I'm not sure why this works but it works. If someone would like to explain it to me I'd appreciate it :D I hope this helps someone either way.

铁憨憨 2024-09-18 16:01:30

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

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

I had the same problem. Here is how I solved it. The solution loads the lib directory and all the subdirectories (not only the direct). Of course you can use this for all directories.

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
剩一世无双 2024-09-18 16:01:30

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

另请检查此 GitHub 讨论链接

As of Rails 5, it is recommended to put the lib folder under app directory or instead create other meaningful name spaces for the folder as services , presenters, features etc and put it under app directory for auto loading by rails.

Please check this GitHub Discussion Link as well.

故事灯 2024-09-18 16:01:30

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

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

来解决它

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

config.autoload_paths does not work for me. I solve it in other way

Ruby on rails 3 do not automatic reload (autoload) code from /lib folder. I solve it by putting inside ApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 
溺渁∝ 2024-09-18 16:01:30

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

require 'mymodule'

在model.rb文件顶部添加:

If only certain files need access to the modules in lib, just add a require statement to the files that need it. For example, if one model needs to access one module, add:

require 'mymodule'

at the top of the model.rb file.

同尘 2024-09-18 16:01:30

正确拼写文件名。

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

回想起来似乎很明显,但这是魔鬼跟踪的向下。如果该类没有在 Rails 根据类名修改而期望的文件中定义,那么它根本就找不到它。

Spell the filename correctly.

Seriously. I battled with a class for an hour because the class was Governance::ArchitectureBoard and the file was in lib/governance/architecture_baord.rb (transposed O and A in "board")

Seems obvious in retrospect, but it was the devil tracking that down. If the class is not defined in the file that Rails expects it to be in based on munging the class name, it is simply not going to find it.

一念一轮回 2024-09-18 16:01:30

有多种原因可能会导致您从 lib 加载时遇到问题 - 请参阅此处了解详细信息 - http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-product/

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

There are several reasons you could have problems loading from lib - see here for details - http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/

  • fix autoload path
  • threadsafe related
  • naming relating
  • ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文