2013-01-24 79 views
2

如果我有一個類似Quests的Rails模型(比如在遊戲中),我會擁有諸如名稱,描述等屬性。但我還需要一些與每個任務相關的代碼來確定玩家是否滿足要求才能完成任務。如何將代碼與Rails模型記錄相關聯?

什麼是一些代碼記錄從模型相關聯的最佳方式?我應該在模型中創建一個quest_function屬性,並在創建新任務時爲models/quest.rb文件中的每條記錄編寫一個函數?這似乎笨重和容易出錯。

應該如何像這樣被Rails中做了什麼?

+0

是每個任務都有可能不同的完成標準 –

+0

@FrederickCheung沒錯的想法。 – DorkRawk

回答

4

那麼,你有幾個選擇。

第一個,像你說的,是在您的記錄存儲的方法/函數的名稱,然後調用該方法時,你需要評估的是探尋這個記錄是否已經完成。在粗略代碼中:

class Quest < ActiveRecord::Base 
    attr_accessible :name, :quest_method 

    def completed? 
     self.send(quest_method) 
    end 

    def end_quest 
     Monster.find_by_name('FINAL BOSS').dead? 
    end 
end 

Quest.create name: 'End Quest', quest_method: 'end_quest' 

這並不像您想象的那麼糟糕。這實際上是single table inheritance的工作原理,但不是存儲方法名稱,而是將類名稱存儲在type列中。

class Quest < ActiveRecord::Base 

    def finished? 
     # default value, or throw an error 
     false 
    end 

end 

class EndQuest < Quest 

    def finished? 
     Monster.find_by_name('END BOSS').dead? 
    end 
end 

EndQuest.create # have to do this for all quests 

在任何一種情況下,您都會將行爲作爲代碼寫入,並在您的記錄中存儲對所需行爲的引用。您必須使用正確的類型或方法名稱手動創建所有記錄,並確保所有內容都保持同步。但至少使用單表繼承ActiveRecord負責處理其中的一些問題。

沒有什麼能阻止你,不過,從存儲代碼本身到數據庫中。

class Quest < ActiveRecord::Base 

    attr_accessible :name, :completed_expr 

    def completed? 
     eval(completed_expr) 
    end 

end 

Quest.create name: 'END QUEST', 
    completed_expr: "Monster.find_by_name('BIG BOSS').dead?" 

這一點,除非你知道自己在做,但正是它給你完全的靈活性,在運行時重寫任務完成的標準當然是潛在的危險,而且容易出錯。最後,如果你想要最複雜和最複雜的,你可能需要考慮使用規則引擎(或者用你自己完成的DSL)來包含你的業務(遊戲世界)規則並存儲它。

class Quest < ActiveRecord::Base 
    attr_accessible :name, :completion_rule 

    def completed? 
     RulesEngine.evaluate(completion_rule) 
    end 
end 

Quest.create name: 'END QUEST', 
    completion_rule: "Monster(name: 'BIG BOSS', state: 'dead')" 

主要優點是通過存儲特定的任務行爲或規則在DSL(這是生Ruby代碼),你會得到一定程度的安全性,你不能只是偶然eval惡意的或錯誤的編碼並把房子放下。

您還可以得到一些效率,如果你的生產規則,以這樣的方式,你可以使用類似的Rete algorithm以評估它們建模。

相關問題