Rails:通过一次又一次地敲击表单路径路径来阻止某人发送表单垃圾

问题描述:

我有一个名为ProficiencyTest的导轨模型,对此,我有email字段的uniqueness验证。Rails:通过一次又一次地敲击表单路径路径来阻止某人发送表单垃圾

还有一种情况用户填写有信息的页面,

那么一旦这些信息被输入,并且电子邮件被确认为唯一的,所以,来电ProficiencyTest.create并渲染测试路径。

测试路径示出了一个简单的表格,和形式update_attributes被称为在@proficiency_test在由create创建的ID的完成后,变化由@proficiency_test.save存储,则的ActionMailer将电子邮件发送到的所述贴切收件人测试结果,最后呈现第三个视图,基本显示测试结果。

这很好,在正常情况下,如果有人登录进行第1页的测试,并且他们已经登录,则页面1被重新渲染,设置为flash.now以显示验证错误。

问题是,通过简单地在浏览器中导航返回表单并显示表单并点击再次提交,从而触发另一个提交并触发该表单,可以非常容易地模拟某人(或网络机器人) ActionMailer成功。

这是我ProficiencyTest控制器的版本:

https://gist.github.com/anonymous/ce169784c7889d6543c6

这里是我的ProficiencyTest型号:

https://gist.github.com/anonymous/a971ce8a2d75190f9486

如何确保一个ID的,一旦proficiency_test已从第一个update_attributes保存,第2页上的提交按钮不会触发另一次保存,另一个电话为ActionMailer

+0

你能更清楚地说明业务逻辑吗?你有一个你希望人们只能接受一次的测试,并且只有在测试完成后才会收到电子邮件。 – Andrew

+0

一个人一次只能进行一次测试,还是人们可以进行多次测试,但每次测试只能进行一次? – Andrew

+0

@Andrew re:你的第一个问题。那是对的。这是一项测试,只应由特定人员(由唯一电子邮件代表)进行一次测试。回答:第二个问题,只有一个测试。许多人都可以接受,但每个人(测试者)都应该是唯一的。这是否澄清了逻辑? – Thalatta

好吧,最简单的方法来思考这个问题,你应该发送邮件来响应模型状态变化,而不是HTTP请求。所以当有人点击“提交”或点击后退按钮并再次提交时,它们会触发新的HTTP请求,但不一定是模型状态更改。

我从上面显示的代码中看到,您实际上在ProficiencyTest#grade方法中触发了邮件程序。一般来说,在模型方法中触发这样的外部行为并不是一个好习惯,尤其是您不想成为idempodent的人。

我认为对你来说更好的方法是将模型中的邮件回调等放入控制器,然后编写控制器方法,使测试只能提交一次。所以,你的方法应该看起来更像是这样的:

def grade 
    @proficiency_test = ProficiencyTest.find(params[:id]) 
    if @proficiency_test.level # the test was already taken 
     # redirect back or show error message 
    else 
     @proficiency_test.update_attributes(proficiency_test_params) 
     @proficiency_test.grade! # this should grade and save the test, but not do mailers 
     # send mailers here 
     # redirect or render success view here 
    end 
    end 

至于发送您的邮件程序,你可以,如果你提取使这变得更干净了这一点你的模型。例如,您可以简单地将能力测试对象传递给这些邮件程序,然后在邮件程序操作中读取熟练测试中的属性。

希望这会有所帮助。

+0

为什么你说“在模型方法中触发这种外部行为不是很好的做法”? –

+0

@Andrew re:重构模型外部的邮件逻辑,你指的是当前'grade'函数中的所有'case'逻辑? – Thalatta

+0

您还有任何阅读rec的RoR最佳实践? – Thalatta