Подтвердить что ты не робот

Предупреждение: постоянная ссылка на уровень

У меня есть четыре модели (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

Как предотвратить это предупреждение (без переименования моих классов)?

4b9b3361

Ответ 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 ​​охватывает области видимости для константы, когда она не найдена в указанной области. Я думаю, что предупреждение - это штраф за то, что он не смог придумать более двух имен переменных.