15

When storing files in a custom directory (Eg: app/presenters/), how do you ensure that namespaced classes are loaded?

For example, if you have:

Rails fails to load MegaMenu::CatalogPresenter:

CatalogPresenter.new
=> #<CatalogPresenter:0x85bca68 @_routes=nil>

MegaMenu::CatalogPresenter.new
(irb):3: warning: toplevel constant CatalogPresenter referenced by MegaMenu::CatalogPresenter
=> #<CatalogPresenter:0x85750a0 @_routes=nil>

I've created a sample Rails 3.2 app that reproduces this problem.

In config/application.rb, the app's configured to load files in app/presenters/.

nickh
  • 4,721
  • 2
  • 29
  • 31

2 Answers2

17

I solved this issue by using a require statement in an initializer. I don't like it much but I liked the structure and class names of my application, they made sense so an initializer was my best solution. In the initializer try:

require File.join(Rails.root, "app", "presenters", "mega_menu", "catalog_presenter")
require File.join(Rails.root, "app", "presenters", "catalog_presenter")

This problem occurs because autoload relies on const_missing being called which won't happen in your case.

When ruby first encounters a reference to MegaMenu::CatalogPresenter, the mega_menu/catalog_presenter.rb file has not been included. Standard ruby behaviour causes it walks up the namespace tree (figure of speech) and it instead finds the top level reference CatalogPresenter as this HAS been included at this point.

David Monagle
  • 1,701
  • 16
  • 19
  • Does this apply in the same way to the app/models directory? I have an app/models/people/data.rb and I get the same exception because Data is already defined. – joshhepworth Jan 25 '13 at 23:19
  • 2
    This will apply anywhere. It's just a matter of how missing constants are resolved. If you make sure that you explicitly require both of the models, you should not run into this issue. – David Monagle Jan 29 '13 at 22:50
0

Creating new toplevel constants inside classes raises this error. You want something more like this in catalog_presenter.rb:

class MegaMenu
  class MegaMenu::CatalogPresenter
  end
end
Veraticus
  • 15,944
  • 3
  • 41
  • 45
  • Thanks for the suggestion, Veraticus. Unfortunately, after making that change, the problem still exists. It seems like Rails doesn't know that it should look for `app/presenters/mega_menu/catalog_presenter.rb` . – nickh Mar 21 '12 at 15:54
  • Oh well, it was worth a shot. :/ The only other suggestion I'd make is to add ```app/presenters/mega_menu``` manually to your autoload paths and see if that corrects it. – Veraticus Mar 21 '12 at 15:55