【问题标题】:ActiveRecord bug with namespaces or expected behavior?带有命名空间或预期行为的 ActiveRecord 错误?
【发布时间】:2020-04-24 12:50:30
【问题描述】:

Rails 4.1.16

Ruby 2.2.7

我有这个 ActiveRecord 模型:

class Something::Type < ActiveRecord::Base

当像这样引用模型时:

Something::Type.find_by_whatever("test")

我收到以下错误:

NoMethodError: undefined method `find_by_whatever' for ActiveRecord::AttributeMethods::Serialization::Type:Class

我知道 Ruby 常量被分解了,所以 Type 作为自己的常量存在,自动加载器首先找到 ActiveRecord::AttributeMethods::Serialization::Type

但是,以“绝对”方式(以冒号为前缀)引用命名空间应该可以解决问题,但结果是相同的。任何想法为什么?

::Something::Type.find_by_whatever("test")

NoMethodError: undefined method `find_by_whatever' for ActiveRecord::AttributeMethods::Serialization::Type:Class

【问题讨论】:

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


    【解决方案1】:

    使用范围结果运算符定义类时的问题是模块嵌套被解析到定义点(使用模块关键字的点)。如果你看一下模块嵌套:

    class Something::Type < ActiveRecord::Base
      puts Module.nesting.inpsect # [Something::Type]
    end
    

    该类甚至没有真正嵌套在 Something 模块中。这会给你一个非常令人惊讶的持续查找:

    module Something
      FOO = "test"
    end
    
    class Something::Type
      puts Foo # gives a uninitialized constant error since its not looking in the Something module
    end
    

    相反,您应该始终使用显式嵌套声明命名空间类:

    module Something
      class Type
        puts Module.nesting.inspect # [Something::Type, Something]
        puts Foo  # test
      end
    end
    

    这给了模块嵌套[Something::Type, Something],这意味着它会在同一个Something命名空间中正确查找常量。

    这是旧的经典自动加载器倾向于掩盖的东西,因为它依赖于猴子补丁Module#const_missing。 Zeitwork 做得不对。

    【讨论】:

    • 谢谢。我仍然对为什么类自动加载器不理解寻找这个完整的常量 (::Something::Type) 而不仅仅是 Type 感到困惑?这似乎是自动加载器中的一个错误。否则,如果推断的命名空间不同,那么声明命名空间有什么意义?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2012-07-16
    相关资源
    最近更新 更多