代码之家  ›  专栏  ›  技术社区  ›  Kyle Decot

警告:引用了顶层常量

  •  42
  • Kyle Decot  · 技术社区  · 11 年前

    我有四个模型( Document , Question , Question::Document Answer ). 在我的 答复 我有模型

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

    这给了我警告

    warning: toplevel constant Document referenced by Question::Document

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

    7 回复  |  直到 11 年前
        1
  •  42
  •   nathanvda    8 年前

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

    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 .

    请注意,如果 文件 首先定义,这也将触发此错误。这取决于代码路径,因此解决此问题的最佳方法是添加 require_dependency 在需要的地方。 看见 here here 了解更多背景信息。

    例如,类似

    require_dependency 'question/document' 
    
    class Answer < ActiveRecord::Base
    
    end  
    

    如果你把文件放在另一个地方,rails无法自动找到它,你就必须明确地要求它,所以rails知道 Question::Document 存在。

    例如,如果您定义 问题::文件 内部 Question 模型,这是一个合理的地方,您必须明确声明对 问题 您的模型 Answer 模型

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

    require_dependency 'question'
    
    class Answer < ActiveRecord::Base
      # ..
    end
    

    虽然平淡无奇 require 有效,最好使用 需求相关性 相反,因为它将与自动加载一起工作,这意味着:在开发过程中的行为与预期一致。

        2
  •  21
  •   Steve    8 年前

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

    对此的一个解决方案是附加 require_dependency 终止 定义外部常量的文件的。

    应用程序/模型/问题.rb

    class Question
      # ...
    end
    
    require_dependency 'question/document'
    

    app/models/question/document.rb应用程序/模型/问题/文档.rb

    class Question
      class Document
        # ...
      end
    end
    

    这迫使 Question::Document 要在 Question 找到常数。通常情况下,如果Rails已经知道顶层 Document 常量,它不会尝试加载 问题::文件 如果还不知道的话。

    参考文献:

        3
  •  5
  •   Tero Tilus    11 年前

    你需要 Question::Document 在引用违规之前定义 Document 参考否则Ruby将开始遍历名称空间以查找 文件 你的 answer.rb 应该有的

    require 'question/document'
    

    最重要的是,假设这是 问题::文件 定义。

        4
  •  1
  •   Community CDub    5 年前

    你可能会看到这样的警告

    /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

        5
  •  0
  •   Fred    11 年前

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

    测试.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
  •  0
  •   mr_ffloyd    8 年前

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

    它在初始化时通过显式解析给定的常量名称 constantize (在加载其他常量之前)。在开发过程中,每次重新加载都会发生这种情况。

        7
  •  -1
  •   7stud    11 年前

    你的意思是这样的:

    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会在封闭作用域中搜索该常量。我认为这个警告是对无法想出两个以上变量名的惩罚。