0

Let's say I've got the following files:

|- app
|  |- helpers
|  |  |- application_helper.rb
|- config
|- |- application.rb
|- lib
|  |- my_module
|  |  |- my_class.rb

I'm trying to make Rails autoload my_module. In application.rb I set

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

I've also managed to obtain the secret knowledge that in order for autoloading to work, the names of modules and classes must match the names of directories and files, so my_class.rb looks like this:

module MyModule
  class MyClass
    # ...
  end
end

Now I want to use MyClass in my application_helper.rb:

module ApplicationHelper

  include MyModule

  def some_method(active_entry = nil)
    someobject = MyClass.new
    #...
  end

end

But I'm getting an error

uninitialized constant ApplicationHelper::MyClass

In order to make this code work I must replace

someobject = MyClass.new

with

someobject = MyModule::MyClass.new

which is ugly. I thought that the include would work like a C++ using namespace, C# using or Java import but apparently it doesn't. So is there any equivalent to the above statements in Ruby?

kamilk
  • 3,829
  • 1
  • 27
  • 40

2 Answers2

1

@ChuckE was close, what you need to do is change config.autoload_paths to

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

The following works for me

  • create directory app/lib/my_module
  • create file in there called my_module.rb

Contents of file:

module MyModule
  class MyClass
    def self.hello
      puts "Hello"
    end
  end
end
  • ensure config.autoload_paths is as noted above
  • run rails console

Output:

[tharrison@mbpro:~/Sites/test] rails c
Loading development environment (Rails 3.2.9)
1.9.3-p194 :001 > include MyModule
 => Object 
1.9.3-p194 :002 > MyClass.hello
Hello
 => nil 

I haven't tried this from the app, but cannot see why it would be any different than running from the rails console.

Oh, and credit where credit is due: got this from Best way to load module/class from lib folder in Rails 3?

Community
  • 1
  • 1
Tom Harrison
  • 13,533
  • 3
  • 49
  • 77
  • Thanks, it sort of works. There's only one problem left: this, and the uglier solution from your previous comment, starts working always after a few failed attempts after the server is started. For every class in `my_module` (alright, there are two of them actually) I get a one-time error `expected (...)/lib/my_module/my_class.rb to define MyClass`. Then my app works flawlessly until I restart the server. What the hell? – kamilk Nov 29 '12 at 14:43
  • Also works from within my app without errors. (Changed `puts "Hello"` to `"Hello"` and then added `include MyModule` to a controller, and in the index method added `logger.debug "Output from MyClass.hello is #{MyClass.hello}"`, which shows in the log when I run. Are your files all named correctly? – Tom Harrison Nov 29 '12 at 15:02
  • Well, I reproduced your steps, creating a new Rails project, and still got the weird error at the first call of `MyClass.hello`. I'm currently upgrading from ruby-1.9.3-p286 to ruby-1.9.3-p327 to see if it helps, though I must say I doubt it. Anyway, if you don't get the error and I do, then I suppose something must be messed up with my installation of RoR :/ – kamilk Nov 29 '12 at 15:18
  • Very skeptical that newer ruby will help. All of what makes this work is relatively basic ruby functionality that has been around forever. – Tom Harrison Nov 29 '12 at 15:41
  • This error is starting to drive me mad. [This question](http://stackoverflow.com/questions/7081782/inconsistent-loaderror-behavior-with-lib-namespacing-autoloading) shed some on the problem to me - it seems that Rails, for some reason, treats lib/my_module folder as root and expects to find class `MyClass` there, instead of `MyModule::MyClass`. Removing the `module` declarations from files solves the problem. I would rather have these classes in a module, but this solution must do for now, or I'll go insane trying to fix it. – kamilk Dec 01 '12 at 15:55
0

instead of this:

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

try this:

config.autoload_paths += Dir["#{config.root}/lib"]
ChuckE
  • 5,610
  • 4
  • 31
  • 59
  • No difference. Though I'll keep this syntax, I'm not a great fan of `%W` TBH. – kamilk Nov 29 '12 at 14:16
  • 1
    well, for me it seems that the sub-directories of lib are not getting included, thought that would work. go to your console and use $: to see if your sub-directory is being referenced. – ChuckE Nov 29 '12 at 14:19
  • 1
    @kamilk -- you need to restart the server for this to re-init. Assuming you have done that, try changing `%W(#{config.root/lib)` to `%W(#{config.root}/lib #{config.root}/lib/my_module)`. The difference in what @ChuckE proposes is that adding `Dir` causes Rails to search the entire subtree, whereas the simple array syntax just enumerates specific directories to check. So I would think his solution should work. – Tom Harrison Nov 29 '12 at 14:22
  • OK, I have confirmed that adding another path to the `%W` form works, and that `Dir["..."]` doesn't work as ChuckE and I thought it would. Searching for more elegant solution :-) – Tom Harrison Nov 29 '12 at 14:32