web-dev-qa-db-ger.com

warnung: Toplevel-Konstante

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)?

40
Kyle Decot

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, stattdessen require_dependency zu verwenden, da dies beim automatischen Laden funktioniert. Dies bedeutet: Verhält sich wie erwartet während der Entwicklung.

39
nathanvda

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:

18
Steve

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.

5
Tero Tilus

Möglicherweise sehen Sie die Warnung so 

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

Nur requiredie 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.

Sie können die Detailerklärung hier lesen

1

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
0
Fred

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.

0
mr_ffloyd