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.first
或 Bar::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 的内置自动加载之间遗漏了一些东西...
.parent
返回的是什么(不是 'parent' class)?
- 为什么我在
.test
中收到错误,但在 rails 控制台中却没有?
- 为什么
Object::Foo
似乎有效?这是正确的做法吗?
- 为什么
ActiveRecord::Base::Foo
有效,但有警告?
- 还有更多 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。
我有这样的文件夹结构:
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.first
或 Bar::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 的内置自动加载之间遗漏了一些东西...
.parent
返回的是什么(不是 'parent' class)?- 为什么我在
.test
中收到错误,但在 rails 控制台中却没有? - 为什么
Object::Foo
似乎有效?这是正确的做法吗? - 为什么
ActiveRecord::Base::Foo
有效,但有警告? - 还有更多 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。