25

I'm trying to load the Tokbox SDK in rails 3. I've placed the library in my /lib directory, so currently my directory structure looks like so:

/lib
  opentok.rb
  /OpenTok
    Exceptions.rb
    OpenTokSDK.rb
    Session.rb

I'm loading all files in the /lib directory using the following in application.rb:

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

Other files I have in the /lib directory are auto-loading just fine, but this library does not load until I add a require 'OpenTok':

ruby-1.9.2-p0 > OpenTok
NameError: uninitialized constant OpenTok
ruby-1.9.2-p0 > OpenTok::OpenTokSDK
NameError: uninitialized constant OpenTok
ruby-1.9.2-p0 > require 'OpenTok'
 => ["OpenTok"]
ruby-1.9.2-p0 > OpenTok
 => OpenTok
ruby-1.9.2-p0 > OpenTok::OpenTokSDK
 => OpenTok::OpenTokSDK 

What is the correct way to load the library in Rails 3?

Jakub Hampl
  • 39,863
  • 10
  • 77
  • 106
Ben
  • 315
  • 1
  • 3
  • 10

2 Answers2

75

Auto-loading works fine as long as the class in your file is a class that is only defined in that file. It doesn't work if you're wanting to re-open an existing class (originally defined in standard Ruby, Rails, or another library) and customize it in some way.

Example of problem:

Here's an example of a file in lib/ that would never get autoloaded:

lib/active_record/base_extensions.rb:

ActiveRecord::Base   # make sure ActiveRecord::Base is loaded
module ActiveRecord::Base::Extensions
  # some methods here
end

class ActiveRecord::Base
  include ActiveRecord::Base::Extensions
end

This file reopens ActiveRecord::Base and adds some methods to that class.

What would trigger this file to get autoloaded?? Nothing! Auto-loading is based on constants, and the constant ActiveRecord::Base has already been loaded (from the activerecord gem).

So referencing the constant ActiveRecord::Base in your app would not cause this particular file to be auto-loaded.

Workaround:

This is what I do to ensure that all my Ruby files under lib/ get required:

Add a new initializer named config/initializers/require_files_in_lib.rb with this contents:

Dir[Rails.root + 'lib/**/*.rb'].each do |file|
  require file
end
Tyler Rick
  • 9,191
  • 6
  • 60
  • 60
  • Generally, you want to use `config.autoload_paths` in Rails, so that it can properly load/unload files. – m33lky Apr 25 '12 at 00:05
  • 2
    I agree, that would generally be a better idea, but it's not always possible, for example if you have a file that reopens an *existing* class rather than defining a *new* class. Any suggestions for what to do in that case? – Tyler Rick Apr 26 '12 at 00:28
  • @m33lky I am trying to load classes in the lib folder and sub directories of the lib folder but rails does not like it. Rails doesn't like sub folders and auto loading. I do not like this work around because it bypasses the class caching but I do not have any other options. I blame rails for being rails. – Vinnyq12 Jul 17 '12 at 09:27
  • thanks a lot, I also post your idea to : http://stackoverflow.com/a/14209677/445908 – Siwei Jan 08 '13 at 07:02
  • 2
    For times when `config.autoload_paths` isn't enough, like when config.threadsafe! is enabled, requiring classes this way works great! – Jeremy Herrman Mar 01 '13 at 19:49
30

The autoloader will snake case the constant, so "OpenTok" would make the autoloader look for "open_tok.rb", not "opentok.rb". Try renaming lib/opentok.rb and it should work fine.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137