Rails.application.config.autoload_paths 和标准 Ruby require/require_relative 有什么区别?

What is the difference between Rails.application.config.autoload_paths and standard Ruby require/require_relative?

我在application.rb中看到如下配置:

config.autoload_paths += %W(#{config.root}/app/models/custom_pack/base)
config.autoload_paths += Dir["#{config.root}/app/models/custom_pack/custom_container/**/"]
config.autoload_paths += Dir["#{config.root}/app/models/custom_pack/helpers/**/"]
config.autoload_paths += Dir["#{config.root}/app/models/custom_pack/extensions/**/"]

在autoload_paths:

Rails.application.config.autoload_paths.grep /custom/
 => ["/Users/dviglione/projects/core/app/models/custom_pack/base", "/Users/dviglione/projects/core/app/models/custom_pack/custom_container/", "/Users/dviglione/projects/core/app/models/custom_pack/helpers/", "/Users/dviglione/projects/core/app/models/custom_pack/extensions/"]

但是没有加载这些文件。因为我得到一个错误:

 `method_missing': undefined method `create_element' for #<MyElement:0x007f82eca39898> 

create_element 方法定义在应该加载的文件之一中。

但是,当我使用 require/require_relative 时,它确实有效:

# /initializers/my_initializer.rb
require "custom_pack/base"

# models/custom_pack/base.rb    
require_relative 'custom_container/base'
require_relative 'custom_container/parent'
require_relative 'custom_container/child'

Dir[File.join(File.expand_path("../helpers", __FILE__), "*_helper.rb")].each { |file| require file }
Dir[File.join(File.expand_path("../extensions", __FILE__), "*_adapter.rb")].each { |file| require file }

根据我从文档中读到的内容,当您使用 require 'erb' 时,Ruby 会在 $LOAD_PATH 中列出的目录中查找文件。也就是说,Ruby 遍历它的所有目录,并为每个目录检查它们是否有一个名为 "erb.rb" 的文件。如果找到其中任何一个,解释器将加载它并结束搜索。否则,它将在列表的下一个目录中再次尝试。如果列表耗尽,则会引发 LoadError。对于自动加载,想法是当像 Post 这样的常量被击中和丢失时,如果有一个 post.rb 文件例如 app/models Rails 将找到它,评估它,并将 Post 定义为副作用。 Rails 有一组类似于 $LOAD_PATH 的目录,可以在其中查找 post.rb。该集合称为 autoload_paths。

那么为什么 require/require_relative 有效,而 autoload_paths 无效?

这里可能会发生很多事情。

1.If 文件遵循以下路径:lib/foo/bar.rb class 需要定义为:

class Foo::Bar
end

2.Autoload 也延迟加载文件,这意味着您的模型仅在您调用它们时加载。 For example:

puts "I was loaded!"

class MyLibrary
end

irb(main):001:0> require 'mylibrary'
I was loaded!
=> true

irb(main):001:0> autoload :MyLibrary, 'mylibrary'
=> nil
irb(main):002:0> MyLibrary.new
I was loaded!
=> #<MyLibrary:0x0b1jef>

至于autoload的实际使用,建议改用require开始。理论上 autoload 听起来不错,但当某些 class 依赖于其他模块时,它可能会导致问题。因为这个autoload is in the process of being deprecated.