Eh bien, vous avez plusieurs options. Le premier, comme vous l'avez dit, est de stocker un nom de méthode/fonction dans votre enregistrement, puis d'appeler cette méthode chaque fois que vous avez besoin d'évaluer si cette quête a été complétée pour cet enregistrement. En code brut:
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'
Ce n'est pas aussi mauvais que vous le pensez. C'est essentiellement comment fonctionne single table inheritance, mais au lieu de stocker un nom de méthode, il stocke le nom de la classe dans la colonne type
. Dans les deux cas, vous écrivez le comportement sous forme de code, et vous stockez simplement une référence au comportement souhaité dans votre enregistrement. Vous devez devez créer tous les enregistrements à la main avec les types appropriés ou les noms de méthode et assurez-vous que tout reste synchronisé. Mais au moins avec l'héritage de table unique, ActiveRecord s'occupe de cela.
Cependant, rien ne vous empêche de stocker du code dans la base de données.
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?"
Ceci, bien sûr est potentiellement dangereuse et sujette aux erreurs, sauf si vous savez exactement ce que vous faites, mais cela vous donne une flexibilité totale de réécrire les critères d'achèvement de la quête à l'exécution. Enfin, si vous voulez le plus de sophistication et de complexité, vous pouvez envisager d'utiliser un moteur de règles (ou de déployer votre propre système complet avec DSL) pour englober vos règles métier et les stocker.
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')"
L'avantage principal est en stockant votre comportement spécifique à la quête ou d'une règle dans un DSL (qui est pas code brut Ruby) vous obtenez un certain niveau de sécurité vous ne pouvez pas accidentellement eval
malveillant ou errante code et ramener la maison.
Vous pouvez également gagner en efficacité si vos règles de production sont modélisées de telle sorte que vous pouvez utiliser quelque chose comme le Rete algorithm pour les évaluer.
L'idée selon laquelle chaque quête a des critères d'achèvement potentiellement différents –
@FrederickCheung Yep. – DorkRawk