2010-08-02 75 views
1

我有一個代表紙牌遊戲的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 

這很好。

我希望能夠在每次擴展中獲得所有卡片的列表。的Moduleconstants方法提供了這樣的一種巧妙的方法 -

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 

但這似乎並不要麼工作,我不能解決原因。通過使用raiseinpect,我確定當我從控制器調用Card.base_game_cards時,結果通常仍然是[]。偶爾在服務器重新啓動後它是正確的,但刷新頁面會將其發送回[]。如果我使用script \ console,列表總是正確的。我試過將需求塊移到控制器類定義的頂部,但這也沒有區別。

現在,我在這個階段非常願意去爲另一種解決方案(可能只是通過活用返回glob文件名列表),但我至少想知道爲什麼方法是行不通的。任何人都可以點亮一些燈(或者 - 更好 - 讓它工作)?

回答

1

是的不幸active_support是「按需」而不是「預先需求」,所以你可能不得不使用你的預加載器。不幸的是,如果你的應用程序處於開發模式,它可能會設置爲「用每個請求重新加載類」,因此你必須禁用rails的這個方便功能,或者確保在需要時重新加載這些文件。

-r

+0

啊,我沒有考慮到「按需重新加載」方面。我會試試這個preloader,看看會發生什麼。 – Chowlett 2010-08-04 10:19:30

+0

啊,是的。如果我關閉cache_classes,我會一致地使用這種技術。謝謝! – Chowlett 2010-08-05 07:54:33

+0

你應該能夠在需要的時候使用類名Preloader來強制他們重新加載,然後你不必關閉緩存......或者通過這樣的手段,我相信。 – rogerdpack 2010-08-05 15:17:44