2013-01-24 4 views
2

Si j'ai un modèle Rails pour quelque chose comme des quêtes (comme dans un jeu), j'aurais des attributs comme le nom, la description, etc. mais j'ai aussi besoin de code associé à chaque quête pour déterminer si un joueur a rempli les conditions requises pour compléter la quête.Comment associer des enregistrements de modèle Rails à du code?

Quelle est la meilleure façon d'associer du code avec des enregistrements d'un modèle? Dois-je créer un attribut quest_function dans le modèle et écrire une fonction pour chaque enregistrement dans le fichier models/quest.rb lorsque je crée une nouvelle quête? Cela semble maladroit et l'erreur sujette.

Comment quelque chose comme ceci devrait-il être fait dans Rails?

+0

L'idée selon laquelle chaque quête a des critères d'achèvement potentiellement différents –

+0

@FrederickCheung Yep. – DorkRawk

Répondre

4

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.

Questions connexes