Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing "warning: toplevel constant B referenced by A::B" with namespaced classes in Rails

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

For example, if you have:

  • app/models/mega_menu.rb
  • app/presenters/catalog_presenter.rb
  • app/presenters/mega_menu/catalog_presenter.rb

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/.

like image 582
nickh Avatar asked Mar 21 '12 15:03

nickh


1 Answers

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.

like image 164
David Monagle Avatar answered Oct 24 '22 07:10

David Monagle