如果我有像Quests这样的Rails模型(比如在游戏中),我会有名称,描述等属性。但我还需要一些与每个任务相关联的代码,以确定玩家是否满足要求以完成任务。
将某些代码与模型中的记录相关联的最佳方法是什么?我应该在模型中创建一个quest_function属性,并在创建新任务时为models / quest.rb文件中的每条记录编写一个函数吗?这似乎很笨拙且容易出错。
如何在Rails中完成这样的事情?
答案 0 :(得分:4)
嗯,你有几种选择。
第一个,就像你说的那样,是在你的记录中存储一个方法/函数名,然后在需要评估该记录的Quest是否已经完成时调用该方法。粗略的代码:
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代码)中,您可以获得一定程度的安全性 - 您不能只是偶然{{1恶意或错误的代码,并把房子打倒。
如果您的制作规则是以Rete algorithm之类的方式对其进行评估,那么您也可以获得一些效率。
答案 1 :(得分:1)
如果您想在创建任务时调用某个函数,那么您应该使用rails强制回调,例如 after_create 或 after_update 。
http://guides.rubyonrails.org/active_record_validations_callbacks.html#callbacks-overview