我有一个需要保存解决方案(测验)值的模块。当然,当解决方案只是像'342'这样的值时,这是微不足道的。但是,有些情况下会发生一些动态计算。例如,如果用户输入值100,可能是为了获得正确的解决方案,我首先必须计算(x * 2)== 300.因此,如果x = 100,解决方案将是错误的
不幸的是,我无法将这样的计算存储在数据库中(至少基于我所知道的)。我可以做的一件事是在我的测验模型中为特定测验添加特定的解决方法。但是,我根本不喜欢这个。这使得课程很难维护,所以我很快放弃了这个想法。
另一个想法是在每个需要它的测验中保存一个新的类对象。这个类将包括所需的所有方法,只需验证计算(使用STI或模块,最有可能后者更容易)。我更喜欢这个想法,我认为这很可能是我要实现的,但在此之前,我想听听你的想法。
你会怎么做?
注意创建模块或类来处理所有解决方案所引起的一个大问题是,我希望将来有多个测验作者。如果他们可以创造自己的挑战,那么以这种方式为他们创建动态解决方案几乎是不可能的。或者,对我来说,监督每个这样的条目并手动创建所需的代码将是一个地狱。
答案 0 :(得分:1)
我不能将这样的计算存储在数据库中(至少基于我所知道的)
当然可以。代码只是文本而ruby是一种动态语言。您可以将正确的解决方案评估表达式存储为文本,然后将其转换为带有eval的代码。
因此,如果该文本字段是问题对象的evaluation_expr字段,其中包含"(x.to_i * 2)== 300" (期望x是提供的答案):
evaluator = eval "lambda { |x| #{question.evaluation_expr} }"
got_it_right = evaluator.call( params[:x] )
这使您能够使用任意复杂的ruby表达式来计算测验问题的正确答案并将其存储在数据库中。
不幸的是,如果您接受来自不受信任的用户的这些表达式的输入,这也存在安全风险,因为您将执行他们在您的服务中作为ruby输入的内容。当然,如果他们必须编写代码来表达他们的问题,这对于多个测验作者来说是一个特有的问题。
答案 1 :(得分:1)
将Ruby代码作为文本存储在数据库中,然后在eval
之前运行解析器(确认它只包含算术表达式,而不是像Dir['/**/*'].each { |f| File.delete(f) }
那样讨厌的东西)。您可以使用Treetop之类的工具来构建解析器。作为奖励,一旦你知道如何使用Treetop,下次你需要构建一个解析器时,它就会很容易。