7

I am using Rails 3.2.2 and want to load all the code in a certain directory recursively. For example:

[Rails root]/lib/my_lib/my_lib.rb
[Rails root]/lib/my_lib/subdir/support_file_00.rb
[Rails root]/lib/my_lib/subdir/support_file_01.rb
...    

Based on Googling, I tried:

config.autoload_paths += ["#{Rails.root.to_s}/lib/my_lib/**"]
config.autoload_paths += ["#{Rails.root.to_s}/lib/my_lib/**/"]
config.autoload_paths += ["#{Rails.root.to_s}/lib/my_lib/**/*"]
config.autoload_paths += ["#{Rails.root.to_s}/lib/my_lib/{**}"]
config.autoload_paths += ["#{Rails.root.to_s}/lib/my_lib/{**}/"]

None of these load any of the code and I get "uninitialized constant" errors.

This loads files directly in /my_lib/, but not subdirectories:

config.autoload_paths += ["#{Rails.root.to_s}/lib/my_lib"]

UPDATE

Thanks for the comments.

I put this in my application.rb:

Dir["#{Rails.root.to_s}/lib/**/*.rb"].each { |file| config.autoload_paths += [file] }

The application launches but classes declared in my library are not available:

> MyClass
NameError: uninitialized constant MyClass
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Ethan
  • 57,819
  • 63
  • 187
  • 237

4 Answers4

11

autoload_paths and friends work only if the given files, or files in the given directories, are named according to the rails naming conventiion.

e.g. if a file some_class.rb is given to autoload_paths, it expcects the file to declare a class SomeClass, and sets up some magic to make any reference to SomeClass load that file on-the-fly.

So if you want to have it only load each of your files as they are needed, then you will have to name your files accordingly, and have one file per class.

If you are happy to load all of the files in a directory tree when rails starts, you can do this:

Dir.glob("/path/to/my/lib/**/*.rb").each { |f| require f }

The above will read every .rb file in /path/to/my/lib, and any directories under it.

Michael Slade
  • 13,802
  • 2
  • 39
  • 44
  • Note that there is a startup time and memory penalty for doing this. The purpose of autoload is to only load classes on demand. If that's not really needed, then by all means put the above code in an initializer and be done with it! – Mark Thomas Apr 16 '12 at 11:59
  • This is the correct answer! Convention is what I was missing :) – jlstr Apr 11 '13 at 22:22
3

Here is a simpler way to add the whole lib directory that does not require .each and feels more straightforward than other answers

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

Refer to @Michael Slade's answer for a nice summary of what autoloading does

Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
2

The autoload paths have to be explicit paths--they can't contain file globs (wildcards).

Therefore, you'll have to do the expansion first:

Dir["#{Rails.root.to_s}/lib/my_lib/**/*.rb"].each do |path|
  config.autoload_paths += [path]
end
Mark Thomas
  • 37,131
  • 11
  • 74
  • 101
  • Is this different somehow from Ben Miller's suggestion, above? It isn't working for me. Still getting "uninitialized constant". (Also, `+=` appears to only work with another Array, so it looks like it needs to be `+= [file]`, otherwise I get "can't convert String into Array)". – Ethan Apr 16 '12 at 01:27
  • You are correct. I was missing the `[]` around path. The "uninitialized constant" error would be due to the file name not being correct for the class referenced. – Mark Thomas Apr 16 '12 at 11:57
  • Yes, when I got my file and class names sorted, it worked. Thanks. – Ethan Apr 16 '12 at 17:22
0

Also you can try .

application.rb :

  config.autoload_paths += %W( #{config.root}/app/model/super_model )
  config.autoload_paths += %W( #{config.root}/lib )
Vik
  • 5,931
  • 3
  • 31
  • 38