Namespaced model in Rails generating NameError: uninitialized constant

Namespaced model in Rails generating NameError: uninitialized constant

我有这样的文件夹结构:

app/
  models/
    bar/
      foo.rb
      connection.rb
    foo.rb

connection.rb 是一个 "abstract class" 用于连接到另一个数据库,所以:

class Bar::Connection < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "outsidedb_#{Rails.env}"
end

bar/foo.rb 用于从 outsidedb 访问 foos table,因此:

class Bar::Foo < Bar::Connection
end

foo.rb 用于从应用程序的数据库访问 foos table,因此:

class Foo < ActiveRecord::Base
end

从 rails 控制台,如果我做 Foo.firstBar::Foo.first 事情表现得像我期望的那样,我从 foos table 分别是应用程序数据库和外部数据库。

但是,如果我尝试从 bar/foo.rb 中访问 Foo,我会得到以下信息:

class Bar::Foo < Bar::Connection
  def self.test
      Bar::Foo.first #=> works
      Foo.first      #=> NameError: uninitialized constant Bar::Foo::Foo
  end

  def self.other_test
    Foo.parent                    #=> Object
    Foo.superclass                #=> ActiveRecord::Base
    Object::Foo.first             #=> works
    ActiveRecord::Base::Foo.first #=> works, but with "warning: toplevel constant 
                                  #   Foo referenced by ActiveRecord::Base::Foo
  end
end

我显然可以让事情正常进行,但我正在寻求对正在发生的事情有更深入的了解。我假设我在 Ruby 的 constant/class 评估和 Rail 的内置自动加载之间遗漏了一些东西...

  1. .parent 返回的是什么(不是 'parent' class)?
  2. 为什么我在 .test 中收到错误,但在 rails 控制台中却没有?
  3. 为什么 Object::Foo 似乎有效?这是正确的做法吗?
  4. 为什么 ActiveRecord::Base::Foo 有效,但有警告?
  5. 还有更多 rails 方法可以完成我所做的事情,而无需重命名我的 foo.rb classes?

我在 Rails '3.2.13'Ruby 1.9.3-p194,你知道的!

您的问题可以通过

解决
::Foo.first

此处::Foo表示top命名空间中的classFoo

你的问题来自于你正在工作的命名空间 (Bar) 中还有另一个 Foo class。所以你应该明确。

至于为什么 Object::Foo 有效(带有警告)的问题,这是 Ruby 中名称查找的(鲜为人知的)行为。请参阅 this 文章了解更多详情。

这里有一些关于 .parent 方法的文档,应该有助于回答您的第一个问题:http://guides.rubyonrails.org/active_support_core_extensions.html#extensions-to-module-parents。向下滚动到相关部分的第 3.3 节。

.parent 方法附带 Active Support,它在 Rails 组件上为 Ruby 提供 Ruby 扩展。 .parent 方法是模块的扩展,它 return 是包含当前 class 的模块的名称。所以,如果你做了 Bar::Foo.parent,return 值应该是 Bar

但是,当 class 没有封闭模块时,return 值将默认为 Object。这就是当您执行 Foo.parent 时发生的情况,因为此处的 Foo 指的是不在 Bar 命名空间中的 Foo class。

相关Rails魔法:https://github.com/rails/rails/blob/c9bbac46ddfc68caff6cd8a95c8d0fd045bd9201/activesupport/lib/active_support/core_ext/module/introspection.rb