J'ai quatre modèles (Document
, Question
, Question::Document
et Answer
). Dans mon modèle 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 empêcher cet avertissement de se produire (sans renommer mes classes)?
Votre structure de dossier/fichier devrait ressembler à ceci:
app/
models/
question/
document.rb
answer.rb
document.rb
question.rb
Et ensuite, Rails trouvera automatiquement les modèles corrects (le nom du modèle sera traduit en un nom de fichier et les espaces de noms seront traduits en dossiers).
Assurez-vous qu'à l'intérieur de votre question/document.rb
, la définition de la classe ressemble à l'une des alternatives suivantes:
class Question::Document
end
ou
class Question
class Document
end
end
Si vous n’écrivez que class Document
, vous redéfinissez la constante de niveau le plus élevé Document
.
Notez que si la variable globale Document
est définie en premier, cela déclenchera également cette erreur. Cela dépend du chemin du code. Le meilleur moyen de résoudre ce problème consiste donc à ajouter un require_dependency
si nécessaire. Voir ici et ici pour plus d'informations.
Par exemple. quelque chose comme
require_dependency 'question/document'
class Answer < ActiveRecord::Base
end
Si vous placez le fichier à un endroit différent, où Rails ne peut pas le trouver automatiquement, vous devrez le demander explicitement, afin que Rails sache que 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 Answer
.
Donc, dans ce cas, dans votre answer.rb
, vous écrirez
require_dependency 'question'
class Answer < ActiveRecord::Base
# ..
end
Alors que plain
require
fonctionne, il est préférable d’utiliserrequire_dependency
car cela 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âche le chargement automatique.
Une solution consiste à ajouter un require_dependency
au 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 que la constante Question
soit trouvée. Normalement, si Rails connaît déjà la constante Document
de niveau supérieur, il ne tentera pas de charger Question::Document
s'il n'est pas déjà connu.
Références:
Vous devez définir Question::Document
avant de référencer la référence Document
incriminée. Sinon, Ruby commencera à parcourir les espaces de noms pour trouver Document
. Votre answer.rb
devrait avoir
require 'question/document'
en plus, 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
Juste require
la classe qui a été référencée, sur 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 un tel avertissement.
Placez 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 cherche dans le niveau supérieur, comme le montre 7stud.
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 une gemme qui introduit une alternative à la solution require_dependency
: heavy_control
Il résout explicitement les noms de constante donnés lors de l'initalisation via constantize
(avant que d'autres constantes ne soient chargées). En outre, il se produit chaque recharge en développement.