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

旧街凉风 提交于 2020-01-06 05:50:33

问题


I see that the following configuration in 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/**/"]

is in the 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/"]

But these files are not being loaded. Because I get an error:

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

That create_element method is defined in one of the files that should have been loaded.

However, when I use require/require_relative, it does work:

# /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 }

From what I read from the documentation, when you use require 'erb', Ruby looks for the file in the directories listed in $LOAD_PATH. That is, Ruby iterates over all its directories and for each one of them checks whether they have a file called "erb.rb". If it finds any of them, the interpreter loads it and ends the search. Otherwise, it tries again in the next directory of the list. If the list gets exhausted, LoadError is raised. For autoloading, the idea is that when a constant like Post is hit and missing, if there's a post.rb file for example in app/models Rails is going to find it, evaluate it, and have Post defined as a side-effect. Rails has a collection of directories similar to $LOAD_PATH in which to look up post.rb. That collection is called autoload_paths.

So why does require/require_relative work, but autoload_paths does not?


回答1:


There's a number of things that could be going on here.

1.If a file is following the path: lib/foo/bar.rb the class needs to be defined like:

class Foo::Bar
end

2.Autoload also lazy loads files, which means your models are only loaded when you call them. 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>

As for the actual usage of autoload, it's recommended to start using require instead. In theory autoload sounds nice but it can cause problems when certain classes are dependent on other modules. Because of this autoload is in the process of being deprecated.



来源:https://stackoverflow.com/questions/51937744/what-is-the-difference-between-rails-application-config-autoload-paths-and-stand

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!