我正在尝试在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
和任何其他命名空间模块?
答案 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.rb
和module.rb
中的相应文件将这些设置为未来模型的默认值。
这个可以全部通过猴子修补ActiveRecord::Base
完成,但这会干扰其他类,例如ActiveRecord::SchemaMigration
,它没有表前缀。< / p>