Rails中的嵌套模块打破table_name_prefix

时间:2014-12-15 12:14:23

标签: ruby-on-rails ruby namespaces

我正在尝试在Rails应用程序中一致地使用嵌套模块/类定义,而不是紧凑(::)语法。但是,它并不总是加载模块文件本身,其中包含table_name_prefix

在Ruby 2.1.1上使用Rails 4.1.8 ...

rails new my_app
...
rails g scaffold User
rails g scaffold Blog::Post

这会创建app/models/blog.rb

module Blog
  def self.table_name_prefix
    'blog_'
  end
end

似乎有很多方法可能会意外阻止Rails自动加载blog.rb。最简单的例子是通过助手。

更改app/helpers/blog/posts_helper.rb

module Blog::PostsHelper
end

为:

module Blog
  module PostsHelper
  end
end

启动服务器,访问/users,然后访问/blog/posts

SQLite3::SQLException: no such table: posts: SELECT "posts".* FROM "posts"

类似的问题可能在其他地方发生,例如在模型测试中。它不仅限于助手。

解决这个问题的最佳方法是什么?显式加载blog.rb和任何其他命名空间模块?

1 个答案:

答案 0 :(得分:0)

一个不依赖于自动加载的解决方案是将模型设置为从以下内容继承,而不是直接从ActiveRecord::Base继承:

class CustomActiveRecordBase < ActiveRecord::Base
  self.abstract_class = true

  # If no table name prefix has been defined, include the namespace/module as
  # table name prefix, e.g., Blog:: -> blog_
  def self.table_name
    # If a table_name_prefix has been defined, follow default behaviour
    return super if full_table_name_prefix.present?

    # Find the prefix, e.g., Blog::Post -> 'blog', User -> ''
    prefix = model_name.name.deconstantize.underscore

    # If no prefix, follow default behaviour
    return super unless prefix.present?

    # Otherwise add the prefix with an underscore
    "#{prefix}_#{super}"
  end
end

然后,无需在self.table_name_prefix中定义blog.rb

根据the default active record templates,可以通过lib/templates/active_record/model/model.rbmodule.rb中的相应文件将这些设置为未来模型的默认值。

这个可以全部通过猴子修补ActiveRecord::Base完成,但这会干扰其他类,例如ActiveRecord::SchemaMigration,它没有表前缀。< / p>