73

I place a file name g.rb in side Rails.root/lib folder The file content is like this:

module Google
end

Then I add

config.autoload_paths += %W(#{config.root}/lib #{Rails.root}/app/delayed_jobs)

to my Rails.root/config/application.rb

However, when I try to invoke Google from rails console, an exception is thrown. The exception goes away only if I execute require 'google'. Why? Shouldn't my file is autoloaded and shouldn't I access the module without any extra require statement?

Phương Nguyễn
  • 8,747
  • 15
  • 62
  • 96

6 Answers6

113

Hmm, I discovered an interesting thing. In order for Rails to auto load my class, the class name should be compliant to the file name and the folder structure. For example, if I want to have Google module autoloaded, I must placed it inside google.rb, directly under /lib (incase I specify autoload from /lib). If I want to auto load Google::Docs, then I either place it inside google.rb or google/docs.rb

Phương Nguyễn
  • 8,747
  • 15
  • 62
  • 96
  • 6
    so is this a bug or a convention? – Blankman Nov 22 '10 at 17:02
  • 8
    I believe this is convention. Rails takes constant names and makes paths out of them. :: gets turned into / for this purpose. So Google::Docs turns into google/docs.rb. You could debate the usefulness of this, but that's my understanding of the current functionality. – Ben Hamill Jan 26 '11 at 22:17
  • 3
    It's not a convention per se, it's the way the Ruby interpreter looks for things, as far as I know – Ghoti May 09 '11 at 16:42
  • 1
    Wow, this just happened to me. I don't really care about the convention, I can rename my modules. I just would have never guessed this. +1. – squarism Oct 17 '11 at 01:45
  • 1
    I had the same problem so I added :: before my class according to the directory and now it complains when ::A references B from the same module, any ideas? – hakunin Feb 08 '12 at 12:03
  • 3
    It's a Rails convention, not a Ruby one – Yarin Oct 31 '13 at 14:14
  • Man I found myself for hours trying to get autoloaded paths working – Donato Feb 07 '15 at 00:14
  • Quickly want to chime in with my experience. First of all for a lot of issues, check out the way Discourse does it. https://github.com/discourse. Personally, I had lib/rhyme_engine.rb then a lib/rhyme_engine folder, and that folder contained file like, engine.rb which looked like class RhymeEngine::Engine – Overload119 Feb 21 '15 at 19:48
27

I had a similar problem with getting my module to run on Heroku. In addition to the autoload naming convention stated by Stephen C, I found out that the module code must be require'd due to a threadsafe assumption made by the Rails' production environment on Heroku (even though threadsafe was commented out in my production.rb configuration file.) As soon as I require'd the module file before calling include on the module, everything started to work.

require 'mymodule'
include Mymodule

Please take a look at this excellent article on the subject of getting Modules to load correctly in Heroku (production).

Alex
  • 9,313
  • 1
  • 39
  • 44
Don Leatham
  • 2,694
  • 4
  • 29
  • 41
  • +1 This should be the accepted answer. The link should help anyone and thread safety was actually my problem. Thank you. – Erik B Nov 09 '11 at 11:58
24

That's because the point of autoload is not to 'require' everything up front (startup penalty). Classes are loaded as they are needed/referenced. In order to do this, you need some way to know where to look for the class. Otherwise, you would have to load every file in the autoload directory in advance to see what classes are declared. It's a tradeoff, but requiring everything in advance (as marbaq suggests) is not autoloading. You can use the autoload command as provided by Ruby, which takes two arguments, the module to load (symbolized, i.e. :Google in your case), and the second argument is the filename, which would be g.rb if lib is in your load path ($:). See the Ruby docs for autoload.

Stephen C
  • 659
  • 6
  • 9
7

Change config.autoload_paths to config.eager_load_paths

(based on Rails issue #6850 and Force reload! from lib directory in rails 3.2 console)

Community
  • 1
  • 1
E. Sambo
  • 901
  • 9
  • 9
1

I faced the same problem just now, and my "solution" (or rather workaround) was to manually require every needed file from Rails.root/lib in my application.rb.

require 'lib/message'
require 'lib/store'
require 'lib/vault/vault.rb'
require 'lib/custom_loggers'

module MyApplication
  class Application < Rails::Application

My next step would be to categorize the files in module folders as you mention.

Fredrik Boström
  • 1,499
  • 1
  • 19
  • 22
-5

i found this solution recently

config/application.rb

module AppName
  class Application < Rails::Application

    # Custom directories with classes and modules you want to be autoloadable.
    config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
    config.autoload_paths += Dir[Rails.root.join('app', 'lib', 'extensions')] 

  end
end

the first config call induces rails to auto-load all sub-directories of the app/models directory so now i can have /app/models/sub_directory/model.rb auto-loaded (handy for organising an app with a large code base)

the second config call induces rails to autoload the lib/extensions directory

hope this helps

note: i believe this is rails 3 specific

ben.m
  • 621
  • 6
  • 10