Ich habe vier Modelle (Document
, Question
, Question::Document
und Answer
). In meinem Modell Answer
habe ich
validates :text,
presence: { :unless => Proc.new{ |a| a.question.is_a? Question::Document } }
Das gibt mir die Warnung
warning: toplevel constant Document referenced by Question::Document
Wie kann ich verhindern, dass diese Warnung auftritt (ohne meine Klassen umzubenennen)?
Ihre Ordner-/Dateistruktur sollte folgendermaßen aussehen:
app/
models/
question/
document.rb
answer.rb
document.rb
question.rb
Und dann findet Rails automatisch die richtigen Modelle (der Modellname wird in einen Dateinamen übersetzt, und Namensräume werden in Ordner übersetzt).
Stellen Sie sicher, dass die Klassendefinition in Ihrem question/document.rb
als eine der folgenden Alternativen erscheint:
class Question::Document
end
oder
class Question
class Document
end
end
Wenn Sie nur class Document
schreiben, definieren Sie die Konstante Document
der obersten Ebene neu.
Wenn das globale Document
zuerst definiert wird, wird auch dieser Fehler ausgelöst. Dies hängt vom Codepfad ab. Daher können Sie am besten einen require_dependency
hinzufügen, wenn dies erforderlich ist. Siehe hier und hier für mehr Hintergrund.
Z.B. so etwas wie
require_dependency 'question/document'
class Answer < ActiveRecord::Base
end
Wenn Sie die Datei an einem anderen Ort ablegen, wo Rails sie nicht automatisch finden kann, müssen Sie sie explizit anfordern, so dass Rails weiß, dass Question::Document
vorhanden ist.
Wenn Sie beispielsweise Question::Document
innerhalb des Question
-Modells definieren, was ein sinnvoller Ort ist, müssen Sie die Abhängigkeit zum Question
-Modell in Ihrem Answer
-Modell explizit angeben.
In diesem Fall schreiben Sie in Ihren answer.rb
require_dependency 'question'
class Answer < ActiveRecord::Base
# ..
end
Normalerweise funktioniert
require
, es ist jedoch vorzuziehen, stattdessenrequire_dependency
zu verwenden, da dies beim automatischen Laden funktioniert. Dies bedeutet: Verhält sich wie erwartet während der Entwicklung.
In Rails darf nicht "required" verwendet werden, da dadurch das automatische Laden beeinträchtigt wird.
Eine Lösung hierfür ist das Anhängen eines require_dependency
an das Ende der Datei, die die äußere Konstante definiert.
app/models/question.rb
class Question
# ...
end
require_dependency 'question/document'
app/models/question/document.rb
class Question
class Document
# ...
end
end
Dadurch wird das Laden der Question::Document
-Klasse erzwungen, nachdem die Konstante Question
gefunden wurde. Wenn Rails bereits die Konstante Document
der obersten Ebene kennt, wird es normalerweise nicht versuchen, Question::Document
zu laden, falls dies nicht bereits bekannt ist.
Verweise:
Sie müssen Question::Document
definiert haben, bevor Sie auf die fehlerhafte Document
-Referenz verweisen. Andernfalls wird Ruby nach Namespaces suchen und nach Document
suchen. Ihr answer.rb
sollte haben
require 'question/document'
darüber hinaus wird angenommen, dass dies der Pfad ist, in dem Question::Document
definiert ist.
Möglicherweise sehen Sie die Warnung so
/path/to/app/models/answer.rb:4: warning: toplevel constant Document referenced by Question::Document
Nur require
die Klasse, auf die verwiesen wurde, in der obersten Datei die diese Warnung auslöst.
In Ihrem Fall wird die folgende Zeile in app/model/answer.rb
eingefügt.
require Rails.root.join('app/models/question/document.rb')
Und nach dem Neustart von Rails server
wird keine solche hässliche Warnung angezeigt.
Ordnen Sie die verschiedenen Klassendefinitionen so an, dass Question::Document
definiert ist, bevor Sie darauf verweisen. Ansonsten geht Ruby auf die oberste Ebene, wie 7stud zeigte.
test.rb
class Document
end
class Question
end
class Question
class Document
end
end
class Answer
puts Question::Document.class
end
Das Ergebnis
$ Ruby test.rb
Class
Ich habe ein Juwel geschrieben, das eine Alternative zur require_dependency
-Lösung vorstellt: heavy_control
Es löst explizit angegebene Konstantennamen bei der Initialisierung über constantize
auf (bevor andere Konstanten geladen werden). Es passiert auch jedes Nachladen in der Entwicklung.