Rails中的Namespaced模型生成NameError:未初始化的常量

我有这样的文件夹结构:

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

connection.rb是一个用于连接到另一个数据库的“抽象类”,因此:

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

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

 class Bar::Foo < Bar::Connection end 

并且foo.rb用于从应用程序的db访问foos表,因此:

 class Foo < ActiveRecord::Base end 

从rails控制台,如果我做Foo.firstBar::Foo.first事情就像我期望的那样,我分别从应用程序db和外部数据库的foos表中获得第一个条目。

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

 class Bar::Foo  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的常量/类评估和Rail的内置自动加载之间缺少某些东西……

  1. 什么是.parent返回(不是’父’类)?
  2. 为什么我在.test得到错误,但是我没有在rails控制台中得到它?
  3. 为什么Object::Foo似乎有效? 这是正确的做法吗?
  4. 为什么ActiveRecord::Base::Foo工作,但有警告?
  5. 有没有更多的rails方式来做我已经完成的事情,而不只是重命名我的一个foo.rb类?

我正在使用Rails '3.2.13'Ruby 1.9.3-p194 ,所以你知道!

您的问题可以解决

 ::Foo.first 

这里::Foo表示顶级命名空间中的类Foo

你的问题来自于你正在使用的命名空间( Bar )中有另一个Foo类。所以你应该是明确的。

至于为什么Object::Foo工作(带警告)的问题,它是Ruby中名称查找的(较少)已知行为。 有关详细信息,请参阅此文章。

这里有一些关于.parent方法的文档,它可以帮助回答你的第一个问题: http : .parent 。 向下滚动到第3.3节,了解相关部分。

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

但是,当类没有封闭模块时,返回值将默认为Object 。 当你执行Foo.parent时会发生这种情况,因为Foo在这里指的是不在Bar命名空间中的Foo类。

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