我有一个代表纸牌游戏的Rails应用程序。有几种不同类型的卡,以及游戏的一些扩展,每个都提供更多的卡。所以我使用了一个cards
表和STI,每个扩展都有一个models子目录和适当命名的模块。像这样:
app/models
- card.rb
+ base_game
- foo.rb
- class BaseGame::Foo < Card
- bar.rb
- class BaseGame::Bar < Card
+ exp_one
- thing.rb
- class ExpOne::Thing < Card
这很有效。
我希望能够获得每个扩展中所有卡的列表。 constants
Module
方法提供了一种巧妙的方法 -
class Card
def self.base_game_cards
BaseGame.constants.map {|c| ("BaseGame::" + c).constantize}.select {|c| c.instance_of?(Class) and c.superclass == Card}
end
end
...除了Rails只在第一次引用时加载给定的模型定义,因此Card.base_game_cards
通常是[]
。
我尝试通过在config / initializers中添加一个文件强制所有模型的预加载来解决这个问题:
preloader.rb:
# Preload all card models from all expansions. This allows us to dynamically
# determine card types by reflection.
Dir.glob("#{RAILS_ROOT}/app/models/*/*.rb").each do |file|
require file
end
但这似乎也不起作用,我无法弄明白为什么。通过使用raise
和inpect
,我确定当我从控制器调用Card.base_game_cards
时,结果通常仍为[]
。服务器重启后,偶尔会出现错误,但刷新页面会将其发送回[]
。如果我使用script \ console,列表总是正确的。我已经尝试将需求块移动到控制器类定义的顶部,但这也没有区别。
现在,我非常愿意在这个阶段寻找另一个解决方案(可能只是改变glob
返回的文件名列表),但我至少想知道为什么这个方法不起作用。任何人都可以解决一些问题(或者 - 甚至更好 - 让它发挥作用)?
答案 0 :(得分:1)
是的,不幸的是,active_support是“按需”而不是“预先要求”,所以你可能不得不使用你的预加载器。不幸的是,如果你的应用程序处于开发模式,它可能会设置为“为每个请求重新加载类”,因此你必须禁用rails的这个方便功能,或者确保在需要时重新加载这些文件。
-r