缺少Rails table_name_prefix

gor*_*tde 20 model module ruby-on-rails prefix

我有以下目录结构

models/foo/setting.rb
models/foo.rb
Run Code Online (Sandbox Code Playgroud)

foo.rb内容

 module Foo
  def self.table_name_prefix
    'foo_'
  end
 end
Run Code Online (Sandbox Code Playgroud)

和setting.rb内容

class Foo::Setting < ActiveRecord::Base
end
Run Code Online (Sandbox Code Playgroud)

一旦我调用Foo::Setting.find…我得到一个SQLException: no such table: settings确实正确的错误,因为该表被命名,foo_settings因此rails似乎忽略为模块Foo指定的表前缀.

我可以做什么让rails考虑前缀?

Fre*_*ung 21

您已在模块(Foo)中定义了一个方法.这并没有神奇地在嵌套在该模块中的类上定义该方法.

我会尝试类似的东西

class Foo < ActiveRecord::Base
  self.abstract_class = true
  self.table_name_prefix = 'foo_'
end
Run Code Online (Sandbox Code Playgroud)

然后继承 Foo

class Foo::Setting < Foo
...
end
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这个答案是正确的.对于我的一些模型,它确实在嵌套类上神奇地定义了该方法,但对于其他模型却没有? (3认同)
  • 对于`table_name_prefix`的[文档](http://apidock.com/rails/ActiveRecord/Base/table_name_prefix/class),OP代码应该有效.我的猜测是它与自动加载器有关(参见我的回答).你的答案仍然有效,所以没有downvote;) (2认同)
  • @m_x下面的答案要好得多,因为它可以确定问题的核心。 (2认同)

m_x*_*m_x 8

这可能是由rails的自动加载器引起的.这样做时:

module Foo
  class Bar
  end
end
Run Code Online (Sandbox Code Playgroud)

然后尝试使用Foo::Bar,自动加载器首先尝试定位app/models/foo/bar.rb.文件已加载,并module Foo在此处定义(尽管是仅包含的模块Bar),因此自动加载器永远不会尝试加载app/models/foo.rb.

这应该只在开发模式下发生,因为在生产模式下,所有文件都require在启动时.

AFAIK有两种解决方法:

欺骗自动加载器

声明你的类使用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
Run Code Online (Sandbox Code Playgroud)

在这里,Foo::Bar.new.baz将失败,除非你引用常量使用Foo::BAZ.例如,在定义ActiveRecord关联时,这可能会变得非常混乱.

需要模块

使用require_dependency:

require_dependency 'foo'
module Foo
  class Bar
  end
end
Run Code Online (Sandbox Code Playgroud)

这是恕我直言的正确解决方案,因为它不会破坏常量查找,但它也有点烦人,因为你必须在每个命名空间文件的顶部添加require语句.

注意 :

这个错误似乎已经在rails 4中解决了.我在rails 3上使用了第二个解决方法,但是我试图在rails 4中重现这个bug并且它不再出现了.我认为他们修改了自动加载器的工作方式...有关详细信息,请参阅自动加载和重新加载常量的rails指南