Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

warning: toplevel constant referenced

I have four models (Document, Question, Question::Document, and Answer). In my Answer model I have

validates :text,
  presence: { :unless => Proc.new{ |a| a.question.is_a? Question::Document } }

This gives me the the warning

warning: toplevel constant Document referenced by Question::Document

How do I prevent this warning from happening (without renaming my classes)?

like image 260
Kyle Decot Avatar asked Aug 29 '13 15:08

Kyle Decot


2 Answers

Your folder/file structure should look as follows:

app/
  models/
    question/
      document.rb
    answer.rb
    document.rb
    question.rb

And then rails will automatically find the correct models (it will translate the model name to a filename, and namespaces are translated to folders).

Make sure that inside your question/document.rb the class definition looks as one of the following alternatives:

class Question::Document
end

or

class Question
  class Document
  end
end

If you write just class Document you are redefining the toplevel constant Document.

Note that if the global Document is defined first, this will also trigger this error. This depends on the code path, so the best way to resolve that, is to add a require_dependency where needed. See here and here for more background.

E.g. something like

require_dependency 'question/document' 

class Answer < ActiveRecord::Base

end  

If you put the file in a different place, where rails cannot automatically find it, you will have to explicitly require it, so rails knows Question::Document exists.

If for instance, you define Question::Document inside the Question model, which is a reasonable place, you will have to explicitly state the dependency to the Question model in your Answer model.

So, in that case, in your answer.rb you will write

require_dependency 'question'

class Answer < ActiveRecord::Base
  # ..
end

While plain require works, it is preferred to use require_dependency instead as it will work with auto-loading, which means: behaves as expected during development.

like image 186
nathanvda Avatar answered Oct 04 '22 13:10

nathanvda


In Rails, you are not supposed to use "require" as it messes up autoloading.

One solution to this is to append a require_dependency to the end of the file that defines the outer constant.

app/models/question.rb

class Question
  # ...
end

require_dependency 'question/document'

app/models/question/document.rb

class Question
  class Document
    # ...
  end
end

This forces the Question::Document class to be loaded after the Question constant is found. Normally, if Rails already knows about the top-level Document constant, it won't attempt to load Question::Document if it's not already known.

References:

  • This example in the Rails Guides on Autoloading and Reloading Constants
  • require_dependency at ApiDock
like image 21
Steve Avatar answered Oct 04 '22 15:10

Steve