This project is archived and is in readonly mode.

#6320 ✓wontfix
Owen

Autoloading behaves weird when class caching is turned off

Reported by Owen | January 21st, 2011 @ 02:11 AM

The algorithm of auto-loading paths in Rails 3 is a bit weird when class caching is turned off. Assuming you add all subdirectories under app/models to the load paths by using the new "config.autoload_paths" setting in config/application.rb:

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

And you have a subdirectory under app/models with name class1 and a file under this subdirectory with name class1.rb. When you are referring any classes under this subdirectory in class1.rb, you have to make sure they are in the namespace of Class1. Otherwise Rails will complain about your referred class is not in the namespace of Class1. In more details, if you have a directory structure like this:

- app
  - models
    - class1
      - class1.rb
      - class1_reference.rb

When you refer to Class1Reference in Class1, you will get "Expected app/models/class1/class1_reference.rb to define Class1::Class1Reference". If the subdirectory is not named class1, strangely this example will work... Let's take a look at a comparing directory structure:

- app
  - models
    - not_class2
      - class2.rb
      - class2_reference.rb

This second example have everything the same as the first one except that the subdirectory name (not_class2) is different from the file name (class2). Surprisingly, this example works as expected. The code of this two examples are available here: https://github.com/jingweno/loading_path_gotchas_in_rails3/tree/mas....

Comments and changes to this ticket

  • Owen

    Owen January 21st, 2011 @ 12:56 PM

    More detail is available at my blog post with comparing examples: http://owenou.com/2011/01/20/loading-path-gotchas-in-rails3.html

  • tsailipu

    tsailipu January 21st, 2011 @ 08:19 PM

    I am investigating this potential bug with a different twist. Glad to find this post and bug report.

    My example is having:
    app/models/user.rb
    app/models/Modu/user.rb

    and have autoload_path::
    config.autoload_paths += %W(#{config.root}/app/models/Modu)

    Where app/models/user.rb is simply:

     class User
       puts "hi User"
     end
    

    and app/Modu/user.rb is simply:

     module Modu
       class User
       puts "hi Modu::User"
       end
     end
    

    Upon "rails c" or "rails server," the following exception will occur:

    hi Modu::User
    /Library/Ruby/Gems/1.8/gems/activesupport-3.0.3/lib/active_support/dependencies.rb:492:in `load_missing_constant': Expected /Users/apps/xyz/app/models/Modu/user.rb to define User (LoadError)
    
  • tsailipu

    tsailipu January 25th, 2011 @ 05:05 AM

    BTW, the bug I reported above happens regardless of caching.

  • José Valim

    José Valim January 25th, 2011 @ 05:41 AM

    • State changed from “new” to “wontfix”
    • Importance changed from “” to “Low”

    Rails is panicking when you add subdirectories of a given directory to autoload paths. In both cases, you will have in the load paths both app/models/ and app/models/client1 (or app/models/Modu) and then Rails heuristic to find which model to load is picking up the one you do not expect to. The ideal way is to not include subdirectories in autoload paths and reference the constants using namespaces.

  • Owen

    Owen January 25th, 2011 @ 04:36 PM

    Hi José,

    How about my example? I don't have two classes with the same name. I have a subdirectory named class1 and a file under it named class1.rb. If class1.rb refers to class1reference.rb, if will also raise exception. I have documented it with a blog post: http://owenou.com/2011/01/20/loading-path-gotchas-in-rails3.html. Please take a look. Thanks.

  • José Valim

    José Valim January 25th, 2011 @ 05:17 PM

    Owen, but you still have app/models/client1 which is a directory. Rails get confused about defining a module with client1 (which it does automatically for directories) or loading the module (which would define a class). Again, the origin of the issue is the same, having a subpath inside another in autoload_paths. This causes ambiguity and any way Rails try to solve it will likely clause conflicts.

  • Owen

    Owen January 25th, 2011 @ 05:35 PM

    Thanks for the clarification, José. So what's the best practice to manage subdirectories in Rails 3? I have too many models and I would like to manage them in different directories. Should I still organize them by having a base file "require" all the files in the subdirectories?

  • tsailipu

    tsailipu January 25th, 2011 @ 05:49 PM

    Sounds like Rails 3 could improve the loading logic: remember the path to the class, then when asked and if there are classes with the same name, check to see whether the references have the path, if not, complain. Bailing out during "rails c" or "rails server" when an autoload path contains the same class name as another in the default app/models path renders Rails 3 brittle.... BTW, Jose, I don't know what changed, but the example I quoted doesn't have a problem in Rails 2 (e.g. 2.3.5). So I don't know why you wouldn't think this is something worth looking into in Rails 3. Thanks for the explanation!

  • Owen

    Owen January 28th, 2011 @ 09:28 PM

    Hi José, can you provide recommendations on how to manage subdirectories in Rails 3. Thanks!

  • myopenid.com (at bobics)

    myopenid.com (at bobics) March 30th, 2011 @ 07:47 AM

    • Tag changed from class cache, class reloading, autoload to class cache, class reloading, autoload, sti

    I realize this ticket is marked "wontfix" but I'd like to add a use case where loading subfolder without a namespace makes sense. My current issue is that I want to use Single Table Inheritance and organize the sub classes in a folder. I should be able to use:

    class Automobile ... end
    class Car < Automobile ... end
    class Truck < Automobile ... end

    And put car.rb and truck.rb under a folder "automobile" without having to scope them. If I use the following:

    class Automobile::Car < Automobile ... end

    Then I get "Automobile::Car" in the "type" column for STI. This is definitely NOT what I want, I'd rather just have "Car".

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages