avertissement: constante de niveau supérieur référencée

J’ai quatre modèles ( Document , Question , Question::Document et Answer ). Dans mon modèle de Answer , j’ai

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

Cela me donne l’avertissement

warning: toplevel constant Document referenced by Question::Document

Comment puis-je empêcher cet avertissement (sans renommer mes classes)?

Votre structure de dossier / fichier doit ressembler à ceci:

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

Et puis, les rails trouveront automatiquement les modèles corrects (cela traduira le nom du modèle en un nom de fichier et les espaces de noms seront traduits en dossiers).

Assurez-vous que dans votre question/document.rb la définition de classe ressemble à l’une des alternatives suivantes:

 class Question::Document end 

ou

 class Question class Document end end 

Si vous écrivez simplement class Document vous redéfinissez le Document toplevel constant.

Notez que si le Document global est défini en premier, cela déclenchera également cette erreur. Cela dépend du chemin de code, donc le meilleur moyen de résoudre ce problème est d’append une require_dependency requirejse. Voir ici et ici pour plus de fond.

Par exemple, quelque chose comme

 require_dependency 'question/document' class Answer < ActiveRecord::Base end 

Si vous placez le fichier dans un endroit différent, où les rails ne peuvent pas le trouver automatiquement, vous devrez le demander explicitement, de sorte que Rails connaît Question::Document existe.

Si, par exemple, vous définissez Question::Document dans le modèle Question , ce qui est un endroit raisonnable, vous devrez indiquer explicitement la dépendance au modèle Question dans votre modèle de Answer .

Donc, dans ce cas, dans votre answer.rb vous écrirez

 require_dependency 'question' class Answer < ActiveRecord::Base # .. end 

Bien que plain require travaux, il est préférable d'utiliser require_dependency car il fonctionnera avec le chargement automatique, ce qui signifie: se comporte comme prévu pendant le développement.

Dans Rails, vous n’êtes pas censé utiliser “require” car cela gêne le chargement automatique.

Une solution à ce problème consiste à append une require_dependency à la fin du fichier qui définit la constante externe.

app / models / question.rb

 class Question # ... end require_dependency 'question/document' 

app / models / question / document.rb

 class Question class Document # ... end end 

Cela force la classe Question::Document à être chargée après la découverte de la constante Question . Normalement, si Rails connaît déjà la constante Document niveau supérieur, il ne tentera pas de charger Question::Document s’il n’est pas déjà connu.

Les références:

  • Cet exemple dans les guides Rails sur le chargement automatique et le rechargement de constantes
  • require_dependency chez ApiDock

Vous devez avoir une Question::Document définie avant de référencer une référence de Document offensante. Sinon, Ruby commencera à parcourir les espaces de noms pour trouver Document . Votre answer.rb devrait avoir

 require 'question/document' 

en plus de cela, en supposant que c’est le chemin où Question::Document est défini.

Vous pourriez voir l’avertissement comme ça

 /path/to/app/models/answer.rb:4: warning: toplevel constant Document referenced by Question::Document 

Exigez simplement la classe qui a été référencée , dans le fichier supérieur qui lance cet avertissement .

Dans votre cas, la ligne ci-dessous ira dans app/model/answer.rb

 require Rails.root.join('app/models/question/document.rb') 

Et, après avoir redémarré le rails server vous ne verrez plus d’avertissement aussi moche.

Vous pouvez lire l’explication détaillée ici

Mettez les différentes définitions de classe dans l’ordre afin que Question::Document soit défini avant de le référencer. Sinon, Ruby regarde dans le niveau supérieur, comme 7stud l’a montré.

test.rb

 class Document end class Question end class Question class Document end end class Answer puts Question::Document.class end 

Le résultat

 $ ruby test.rb Class 

J’ai écrit un joyau qui présente une alternative à la solution require_dependency : heavy_control

Il résout explicitement les noms de constantes données lors de l’initialisation via la constantize (avant que d’autres constantes ne soient chargées). Il arrive aussi chaque rechargement en développement.

Tu veux dire comme cela:

 Document = 'hello' class Question end class Animal puts Question::Document end class Question class Document end end --output:-- 1.rb:7: warning: toplevel constant Document referenced by Question::Document hello 

Il semble que les recherches de ruby ​​contenant des étendues pour une constante ne se trouvent pas dans la scope spécifiée. Je pense que l’avertissement est une pénalité pour avoir été incapable de concevoir plus de deux noms de variables.