我有一個代表紙牌遊戲的Rails應用程序。有幾種不同類型的卡,以及一些遊戲的擴展,每個提供更多的卡。所以我使用一個cards
表和STI,每個擴展都有一個models子目錄和一個適當命名的模塊。像這樣:Rails內部反射問題
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
這很好。
我希望能夠在每次擴展中獲得所有卡片的列表。的Module
的constants
方法提供了這樣的一種巧妙的方法 -
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
是[]
。
我試圖通過強制所有型號的預壓工作的這一輪,通過將文件到配置/初始化:
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
文件名列表),但我至少想知道爲什麼這方法是行不通的。任何人都可以點亮一些燈(或者 - 更好 - 讓它工作)?
啊,我沒有考慮到「按需重新加載」方面。我會試試這個preloader,看看會發生什麼。 – Chowlett 2010-08-04 10:19:30
啊,是的。如果我關閉cache_classes,我會一致地使用這種技術。謝謝! – Chowlett 2010-08-05 07:54:33
你應該能夠在需要的時候使用類名Preloader來強制他們重新加載,然後你不必關閉緩存......或者通過這樣的手段,我相信。 – rogerdpack 2010-08-05 15:17:44