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
?
好吧,最简单的方法来思考这个问题,你应该发送邮件来响应模型状态变化,而不是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
至于发送您的邮件程序,你可以,如果你提取使这变得更干净了这一点你的模型。例如,您可以简单地将能力测试对象传递给这些邮件程序,然后在邮件程序操作中读取熟练测试中的属性。
希望这会有所帮助。
你能更清楚地说明业务逻辑吗?你有一个你希望人们只能接受一次的测试,并且只有在测试完成后才会收到电子邮件。 – Andrew
一个人一次只能进行一次测试,还是人们可以进行多次测试,但每次测试只能进行一次? – Andrew
@Andrew re:你的第一个问题。那是对的。这是一项测试,只应由特定人员(由唯一电子邮件代表)进行一次测试。回答:第二个问题,只有一个测试。许多人都可以接受,但每个人(测试者)都应该是唯一的。这是否澄清了逻辑? – Thalatta