42

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

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

这给了我警告

warning: toplevel constant Document referenced by Question::Document

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

4

7 回答 7

41

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

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在需要的地方添加一个。有关更多背景信息,请参见此处此处

例如像

require_dependency 'question/document' 

class Answer < ActiveRecord::Base

end  

如果您将文件放在不同的位置,rails 无法自动找到它,您将必须明确要求它,以便 rails 知道Question::Document存在。

例如,如果您在模型Question::Document内部定义Question,这是一个合理的位置,您将必须在Question模型中明确声明对模型的依赖关系Answer

所以,在那种情况下,answer.rb你会写

require_dependency 'question'

class Answer < ActiveRecord::Base
  # ..
end

虽然plainrequire可以工作,但最好使用require_dependency它,因为它将与自动加载一起工作,这意味着:在开发过程中表现如预期。

于 2013-09-11T09:29:26.057 回答
21

在 Rails 中,您不应该使用“require”,因为它会破坏自动加载。

对此的一种解决方案是将 a 附加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

参考:

于 2015-11-21T19:08:53.527 回答
5

您需要Question::Document在引用违规Document引用之前进行定义。否则 Ruby 将开始遍历命名空间直到 find Document。你answer.rb应该有

require 'question/document'

最重要的是,假设这Question::Document是定义的路径。

于 2013-09-06T20:17:13.923 回答
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您将不会看到如此丑陋的警告。

您可以在此处阅读详细说明

于 2013-09-07T16:05:18.007 回答
0

将各种类定义按顺序排列,以便Question::Document在您引用它之前对其进行定义。否则,如 7stud 所示,ruby 会进入顶层。

测试.rb

class Document
end

class Question
end

class Question
  class Document
  end
end

class Answer
  puts Question::Document.class
end

结果

$ ruby test.rb
Class
于 2013-09-06T21:20:17.423 回答
0

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

它在初始化时显式解析给定的常量名称constantize(在加载其他常量之前)。它也发生在开发中的每次重新加载。

于 2016-09-27T09:52:16.920 回答
-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​​ 搜索封闭范围的常量。我认为警告是对无法想出两个以上变量名的惩罚。

于 2013-08-29T16:17:27.487 回答