Ruby-on-rails 警告:引用了顶级常量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18515100/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
warning: toplevel constant referenced
提问by Kyle Decot
I have four models (Document, Question, Question::Document, and Answer). In my Answermodel I have
我有四个模型(Document,Question,Question::Document和Answer)。在我的Answer模型中,我有
validates :text,
presence: { :unless => Proc.new{ |a| a.question.is_a? Question::Document } }
This gives me the the warning
这给了我警告
warning: toplevel constant Document referenced by Question::Document
warning: toplevel constant Document referenced by Question::Document
How do I prevent this warning from happening (without renaming my classes)?
如何防止发生此警告(不重命名我的类)?
采纳答案by nathanvda
Your folder/file structure should look as follows:
您的文件夹/文件结构应如下所示:
app/
models/
question/
document.rb
answer.rb
document.rb
question.rb
And then rails will automatically find the correct models (it will translate the model name to a filename, and namespaces are translated to folders).
然后 rails 会自动找到正确的模型(它将模型名称转换为文件名,并将命名空间转换为文件夹)。
Make sure that inside your question/document.rbthe class definition looks as one of the following alternatives:
确保在您question/document.rb的类定义中看起来像以下选项之一:
class Question::Document
end
or
或者
class Question
class Document
end
end
If you write just class Documentyou are redefining the toplevel constant Document.
如果你只是写class Document你正在重新定义顶级常量Document。
Note that if the global Documentis defined first, this will also trigger this error. This depends on the code path, so the best way to resolve that, is to add a require_dependencywhere needed.
See hereand herefor more background.
注意,如果Document先定义了全局,也会触发这个错误。这取决于代码路径,因此解决该问题的最佳方法是require_dependency在需要的地方添加一个。有关更多背景信息,请参见此处和此处。
E.g. something like
例如类似的东西
require_dependency 'question/document'
class Answer < ActiveRecord::Base
end
If you put the file in a different place, where rails cannot automatically find it, you will have to explicitly require it, so rails knows Question::Documentexists.
如果你把文件放在一个不同的地方,rails 不能自动找到它,你必须明确地要求它,所以 rails 知道Question::Document存在。
If for instance, you define Question::Documentinside the Questionmodel, which is a reasonable place, you will have to explicitly state the dependency to the Questionmodel in your Answermodel.
例如,如果您Question::Document在Question模型内部定义,这是一个合理的位置,则必须在Question模型中明确说明对模型的依赖关系Answer。
So, in that case, in your answer.rbyou will write
所以,在这种情况下,answer.rb你会写
require_dependency 'question'
class Answer < ActiveRecord::Base
# ..
end
While plain
requireworks, it is preferred to userequire_dependencyinstead as it will work with auto-loading, which means: behaves as expected during development.
虽然普通
require工作,但最好使用require_dependency它,因为它将与自动加载一起工作,这意味着:在开发过程中按预期运行。
回答by Steve
In Rails, you are not supposed to use "require" as it messes up autoloading.
在 Rails 中,您不应该使用“require”,因为它会扰乱自动加载。
One solution to this is to append a require_dependencyto the endof the file that defines the outer constant.
对此的一种解决方案是将 a 附加require_dependency到定义外部常量的文件末尾。
app/models/question.rb
应用程序/模型/question.rb
class Question
# ...
end
require_dependency 'question/document'
app/models/question/document.rb
应用程序/模型/问题/document.rb
class Question
class Document
# ...
end
end
This forces the Question::Documentclass to be loaded after the Questionconstant is found. Normally, if Rails already knows about the top-level Documentconstant, it won't attempt to load Question::Documentif it's not already known.
这会强制在找到常量Question::Document后加载类Question。通常情况下,如果 Rails 已经知道顶级Document常量,Question::Document如果它不知道,它就不会尝试加载。
References:
参考:
- This examplein the Rails Guides on Autoloading and Reloading Constants
- require_dependencyat ApiDock
- Rails Guides on Autoloading and Reloading Constants 中的这个例子
- ApiDock 上的require_dependency
回答by Tero Tilus
You need to have Question::Documentdefined before referencing offending Documentreference. Otherwise Ruby will start traversing namespaces up to find Document. Your answer.rbshould have
您需要Question::Document在引用违规Document引用之前进行定义。否则 Ruby 将开始遍历命名空间以查找Document. 你answer.rb应该有
require 'question/document'
on top of it, assuming that's the path where Question::Documentis defined.
最重要的是,假设这Question::Document是定义的路径。
回答by Paritosh Piplewar
You might be seeing the warning like this
您可能会看到这样的警告
/path/to/app/models/answer.rb:4: warning: toplevel constant Document referenced by Question::Document
Just requirethe class which was referenced, on the top file which is throwing
this warning.
只是require被引用的类,在抛出此警告的顶级文件中。
In your case the below line will go in app/model/answer.rb
在您的情况下,以下行将进入 app/model/answer.rb
require Rails.root.join('app/models/question/document.rb')
And, after restarting the rails serveryou won't see such ugly warning.
而且,重新启动后,rails server您将不会看到如此丑陋的警告。
You can read detail explanation here
您可以在此处阅读详细说明
回答by mr_ffloyd
I've wrote a gem which introduce alternative to require_dependencysolution: heavy_control
我写了一个 gem,它介绍了require_dependency解决方案的替代方案:heavy_control
It explicitly resolves given constant names on initalization via constantize(before other constants are loaded). Also it happens each reload in development.
它在初始化时显式解析给定的常量名称constantize(在加载其他常量之前)。在开发过程中每次重新加载都会发生这种情况。
回答by Fred
Put the various class definitions in order so that Question::Documentis defined before you reference it. Otherwise ruby goes looking in the toplevel, as 7stud showed.
将各种类定义按顺序排列,以便Question::Document在引用它之前进行定义。否则 ruby 会在顶层查找,如 7stud 所示。
test.rb
测试文件
class Document
end
class Question
end
class Question
class Document
end
end
class Answer
puts Question::Document.class
end
The result
结果
$ ruby test.rb
Class
回答by 7stud
You mean like this:
你的意思是这样的:
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
It looks like ruby searches enclosing scopes for a constant when it isn't found in the specified scope. I think the warning is a penalty for being unable to think up more than two variable names.
当在指定的范围内找不到常量时,它看起来像 ruby 搜索封闭范围的常量。我认为警告是无法想出两个以上变量名称的惩罚。

