我有以下目录结构
models/foo/setting.rb
models/foo.rb
foo.rb内容
module Foo
def self.table_name_prefix
'foo_'
end
end
和setting.rb内容
class Foo::Setting < ActiveRecord::Base
end
当我调用Foo::Setting.find…
时,我收到错误SQLException: no such table: settings
,这确实是正确的,因为该表名为foo_settings
,因此rails似乎忽略为模块指定的表前缀FOO。
我可以做什么让rails考虑前缀?
答案 0 :(得分:20)
您已在模块内定义了一个方法(Foo)。这并没有神奇地在嵌套在该模块中的类上定义该方法。
我会尝试像
这样的东西class Foo < ActiveRecord::Base
self.abstract_class = true
self.table_name_prefix = 'foo_'
end
然后继承自Foo
class Foo::Setting < Foo
...
end
答案 1 :(得分:7)
这可能是由rails的自动加载器引起的。这样做时:
The error occurred while parsing the regular expression fragment: '/([0-9]{5}>>>HERE>>>)]'.
然后尝试使用module Foo
class Bar
end
end
,自动加载器首先尝试找到Foo::Bar
。该文件已加载,此处定义了app/models/foo/bar.rb
(虽然该模块仅包含module Foo
),因此自动加载器永远不会尝试加载Bar
。
这应该只在开发模式下进行,因为在生产模式下,所有文件在启动时都是app/models/foo.rb
。
AFAIK有两种解决方法:
欺骗自动加载器
使用require
声明您的课程,以强制自动加载器解析class Foo::Bar
的常量查找。
这有令人讨厌的副作用,Foo
内的常量查找不会限定在Bar
内,例如:
Foo
此处,# app/models/foo.rb
module Foo
BAZ = "baz"
end
# app/models/foo/bar.rb
class Foo::Bar
def baz
BAZ
end
end
将失败,除非您使用Foo::Bar.new.baz
引用常量。例如,在定义ActiveRecord关联时,这可能会变得非常混乱。
需要模块
使用Foo::BAZ
:
require_dependency
这是恕我直言的正确解决方案,因为它不会破坏常量查找,但它也有点烦人,因为你必须在每个命名空间文件的顶部添加require语句。
注意:
这个bug似乎已经在rails 4中解决了。我在rails 3上使用了第二个解决方法,但是我试图重现rails 4中的bug并且它不再出现了。我认为他们修改了自动加载器的工作方式...有关详细信息,请参阅the rails guides on autoloading and reloading constants
答案 2 :(得分:1)
我有同样的问题。通过更改我的应用程序的命名空间或模型来解决它。
看看这个question。对应用程序使用与模型相同的命名空间会导致模型无法正确获取父命名空间table_name_prefix。
答案 3 :(得分:0)
只需在命名空间的模型目录中创建一个基类,并在其中包含Foo,然后从基类扩展模型。
说我有app/models/foo.rb
module Foo
def self.table_name_prefix
'tble_prefix_'
end
end
然后在app/models/foo/base_record.rb
require_dependency 'foo'
module Foo
class BaseRecord < ActiveRecord::Base
self.abstract_class = true
end
end
然后从BaseRecord
module Foo
class Bar < BaseRecord
end
end