Rails: Organizing Models in Subfolders Having Warning: Toplevel Constant a Referenced by B::A

Rails: organizing models in subfolders having warning: toplevel constant A referenced by B::A

Update: This years Christmas present was the release of Ruby 2.5.0 with which this error won't happen anymore. With Ruby 2.5+ you will either get the constant you asked for or an error. For older Ruby versions read on:

Your User::File class is not loaded. You have to require it (e.g. in user.rb).

The following happens when ruby/rails sees User::Info and evaluates it (simplified; only User is defined yet).

  • check if User::Info is defined - it is not (yet)
  • check if Info is defined - it is not (yet)
  • uninitialized constant -> do rails magic to find the user/info.rb file and require it
  • return User::Info

Now lets do it again for User::File

  • check if User::File is defined - it is not (yet)
  • check if File is defined - it is (because ruby has a built in File class)!
  • produce a warning, because we've been asked for User::File but got ::File
  • return ::File

We observe that the rails magic, that automatically requires files for (yet) unknown constants, does not work for User::File because File is not unknown.

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

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.

Best way to separate Sequel model definitions into different file?

Of course it's possible. Extract the definitions into their own file (say, models.rb), and put require_relative('models') where they used to be.

Or you can even put each model in its own file in a directory, say models/person.rb..., and then

Dir["models/*.rb"].each { |file| require_relative(file) }

Showing a warning message when before_create fails?

A before_create isn't the right place to be reporting errors. Your before_create should try to set the value and then a validator should check if it is there, if the validator doesn't find the value then you'll get your error message and such. So, if your attribute is called pancakes, then you'd have something like this:

before_validation :stuff_web_api_value_into_pancakes, :if => :new_record?
validates_presence_of :pancakes

You could, of course, use a different validator than validates_presence_of, that's just there for illustrative purposes. And you'll want a before_validation hook to get things to happen in the right order, the :if => :new_record? will only run the hook when you're creating a new model.



Related Topics



Leave a reply



Submit