Предупреждение: постоянная ссылка на уровень
У меня есть четыре модели (Document
, Question
, Question::Document
и Answer
). В моей модели Answer
у меня есть
validates :text,
presence: { :unless => Proc.new{ |a| a.question.is_a? Question::Document } }
Это дает мне предупреждение
warning: toplevel constant Document referenced by Question::Document
Как предотвратить это предупреждение (без переименования моих классов)?
Ответы
Ответ 1
Структура вашей папки/файла должна выглядеть следующим образом:
app/
models/
question/
document.rb
answer.rb
document.rb
question.rb
И тогда рельсы автоматически найдут правильные модели (он переведет имя модели в имя файла, а пространства имен будут переведены в папки).
Убедитесь, что внутри question/document.rb
определение класса выглядит как один из следующих вариантов:
class Question::Document
end
или
class Question
class Document
end
end
Если вы пишете только class Document
, вы переопределяете константу toplevel Document
.
Обратите внимание, что если глобальный Document
определяется первым, это также вызовет эту ошибку. Это зависит от пути кода, поэтому лучший способ решить это - добавить require_dependency
там, где это необходимо.
Подробнее см. здесь и здесь.
например. что-то вроде
require_dependency 'question/document'
class Answer < ActiveRecord::Base
end
Если вы поместите файл в другое место, где рельсы не могут автоматически найти его, вам придется явно потребовать его, поэтому рельсы знают Question::Document
.
Если, например, вы определяете Question::Document
внутри модели Question
, что является разумным местом, вам нужно явно указать зависимость к модели Question
в вашей модели Answer
.
Итак, в этом случае в answer.rb
вы напишете
require_dependency 'question'
class Answer < ActiveRecord::Base
# ..
end
В то время как работает обычная require
, вместо этого используется require_dependency
, поскольку она будет работать с автоматической загрузкой, что означает: ведет себя так, как ожидалось во время разработки.
Ответ 2
В Rails вы не должны использовать "require", поскольку это забивает автозагрузку.
Одним из решений этого является добавление require_dependency
в конец файла, определяющего внешнюю константу.
приложение/модели/question.rb
class Question
# ...
end
require_dependency 'question/document'
приложение/модели/вопрос/document.rb
class Question
class Document
# ...
end
end
Это заставляет класс Question::Document
загружаться после нахождения константы Question
. Обычно, если Rails уже знает о константе верхнего уровня Document
, она не будет пытаться загрузить Question::Document
, если она еще не известна.
Литература:
Ответ 3
Вы должны иметь Question::Document
, указанный перед ссылкой на оскорбительную ссылку Document
. В противном случае Ruby начнет перемещение пространств имен, чтобы найти Document
. Ваш answer.rb
должен иметь
require 'question/document'
поверх него, считая, что путь, где Question::Document
определен.
Ответ 4
Возможно, вы увидите предупреждение, подобное этому
/path/to/app/models/answer.rb:4: warning: toplevel constant Document referenced by Question::Document
Просто require
класс, на который ссылался, в верхнем файле , который бросает
это предупреждение.
В вашем случае нижняя строка войдет в app/model/answer.rb
require Rails.root.join('app/models/question/document.rb')
И после перезапуска rails server
вы не увидите такого уродливого предупреждения.
Ответ 5
Поместите различные определения классов в порядок, чтобы Question::Document
был определен, прежде чем ссылаться на него. В противном случае рубин будет искать в верхнем углу, как показал 7stud.
test.rb
class Document
end
class Question
end
class Question
class Document
end
end
class Answer
puts Question::Document.class
end
Результат
$ ruby test.rb
Class
Ответ 6
Я написал камень, который представляет альтернативу решению require_dependency
: heavy_control
Он явно разрешает заданные константные имена при инициализации через constantize
(до загрузки других констант). Также это происходит при каждой перезагрузке.
Ответ 7
Вы имеете в виду следующее:
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
Похоже, поиск ruby охватывает области видимости для константы, когда она не найдена в указанной области. Я думаю, что предупреждение - это штраф за то, что он не смог придумать более двух имен переменных.