警告:toplevel常量引用

时间:2013-08-29 15:29:25

标签: ruby-on-rails ruby ruby-on-rails-4

我有四个模型(DocumentQuestionQuestion::DocumentAnswer)。在我的Answer模型中,我有

validates :text,
  presence: { :unless => Proc.new{ |a| a.question.is_a? Question::Document } }

这给了我警告

warning: toplevel constant Document referenced by Question::Document

如何防止发生此警告(不重命名我的课程)?

7 个答案:

答案 0 :(得分:40)

您的文件夹/文件结构应如下所示:

app/
  models/
    question/
      document.rb
    answer.rb
    document.rb
    question.rb

然后rails将自动找到正确的模型(它会将模型名称转换为文件名,名称空间将转换为文件夹)。

确保question/document.rb类定义中的内容看起来像下列其中一种:

class Question::Document
end

class Question
  class Document
  end
end

如果你只是写class Document,那么你正在重新定义顶级常数Document

请注意,如果首先定义全局Document,则也会触发此错误。这取决于代码路径,因此解决这个问题的最佳方法是在需要的地方添加require_dependency。 有关更多背景信息,请参阅herehere

E.g。

之类的东西
require_dependency 'question/document' 

class Answer < ActiveRecord::Base

end  

如果您将文件放在其他位置,rails无法自动找到它,则必须明确要求它,因此rails知道Question::Document存在。

例如,如果您在Question::Document模型中定义Question,这是一个合理的位置,您必须明确说明{{1}模型中的Question模型的依赖关系模型。

那么,在这种情况下,在你的Answer中你会写

answer.rb
  

虽然普通require_dependency 'question' class Answer < ActiveRecord::Base # .. end 有效,但最好使用require,因为它可以自动加载,这意味着:在开发过程中表现如预期。

答案 1 :(得分:18)

在Rails中,你不应该使用“require”,因为它会弄乱自动加载。

对此的一个解决方案是将require_dependency附加到定义外部常量的文件的 end

应用/模型/ question.rb

class Question
  # ...
end

require_dependency 'question/document'

应用/模型/问题/ document.rb

class Question
  class Document
    # ...
  end
end

这会强制在找到Question::Document常量后加载Question类。通常情况下,如果Rails已经知道顶级Document常量,那么如果它还不知道,它将不会尝试加载Question::Document

<强>参考文献:

答案 2 :(得分:5)

在引用违规Question::Document引用之前,您需要定义Document。否则Ruby将开始遍历名称空间以查找Document。您的answer.rb应该

require 'question/document'

在它之上,假设这是定义Question::Document的路径。

答案 3 :(得分:1)

你可能会看到像这样的警告

/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后,您将看不到这种丑陋的警告。

You can read detail explanation here

答案 4 :(得分:0)

按顺序放置各种类定义,以便在引用之前定义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

答案 5 :(得分:0)

我写了一个宝石,介绍require_dependency解决方案的替代方案:heavy_control

通过constantize(在加载其他常量之前)明确地解决了关于初始化的常量名称。它也会在开发中重新加载。

答案 6 :(得分:-1)

你的意思是这样的:

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搜索包含范围的常量。我认为警告是因为无法想到两个以上的变量名称而受到惩罚。