[英]In rails controllers, how to prevent double submit (when user double-clic submit button or hit enter twice)?
Well, everything's in the title but I'll explain a little more :-) 好吧,一切都在标题中,但我会解释一下:-)
My rails app contain many forms (Ajaxified or not). 我的rails应用程序包含许多表单(Ajaxified或不Ajaxified)。
To prevent users to submit twice or more some forms, I use Javascript. 为了防止用户提交两次或更多的表格,我使用Javascript。
There's my scenario for a Ajaxified form : 有一个Ajaxified表单的场景:
Now I want to add server side code to keeps things really clean if the user bypass the javascript. 现在我想添加服务器端代码,以便在用户绕过javascript时保持真正干净。
Any suggestions? 有什么建议?
I use 4 method for 4 scenarios, please firstly prefer my awnser here: Prevent double submits in a Rails AJAX form 我在4个场景中使用4方法,请首先在这里选择我的awnser: 防止在Rails AJAX表单中提交双重提交
use stopImmediatePropagation and add a click event to the target dom. 使用stopImmediatePropagation并将click事件添加到目标dom。
/**
* 防止按钮重复点击。
* NOTICE: #1 需要在作用点之前调用此方法 #2 stopImmediatePropagation 会阻止后面的所有事件包括事件冒泡
* @delay_duration 两次点击的间隔时间
*/
$.fn.preventMultipleClick = function (delay_duration) {
delay_duration = delay_duration || 3000;
var last_click_time_stamp = 0;
var time_duration = 0;
$(this).bind('click', function (event) {
time_duration = last_click_time_stamp ? event.timeStamp - last_click_time_stamp : 0;
//console.debug("preventMultipleClick", last_click_time_stamp, time_duration);
if (time_duration && time_duration < delay_duration) {
event.stopImmediatePropagation();
} else {
//console.debug("skip preventMultipleClick~");
last_click_time_stamp = event.timeStamp;
}
});
};
use ajax's beforeSend attribut. 使用ajax的beforeSend attribut。
/**
* 使用:
* 在jquery的ajax方法中加入参数:beforeSend
* 例如:beforeSend: function(){return $.preventMultipleAjax(event, 5000)}
*
* @param event
* @param delay_duration
* @returns {boolean}
*/
$.preventMultipleAjax = function (event, delay_duration) {
delay_duration = delay_duration || 3000;
var target = $(event.target);
var last_click_time_stamp = target.attr("_ajax_send_time_stamp") || 0;
var time_duration = last_click_time_stamp ? event.timeStamp - last_click_time_stamp : 0;
//console.debug("preventMultipleAjax", last_click_time_stamp, time_duration);
if (time_duration && time_duration < delay_duration) {
return false;
} else {
//console.debug("skip preventMultipleAjax~");
target.attr("_ajax_send_time_stamp", event.timeStamp);
return true;
}
};
<%= f.submit "Save annotation", :disable_with => "Saving...", :class => "btn btn-primary", :id => "annotation-submit-button" %>
or: disable:仅仅对表单元素,按钮等起作用,会阻止其上的事件触发 或:禁用:仅仅对表单元素,按钮等起作用,会阻止其上的事件触发
<input type="submit" value="submit" />
<input type="button" value="button" />
<input type="image" value="image" />
This is the gem: https://github.com/mlanett/redis-lock 这是宝石: https : //github.com/mlanett/redis-lock
Redis.current.lock("#{current_user.id}.action_name") do
# Some code
end
您可以在提交标记中添加选项:disable_with =>“Please Wait ...”。
Try using Redis locking and surround your block with something like 尝试使用Redis锁定并用类似的东西包围你的块
Redis.current.lock("#{current_user.id}.action_name") do
# Some code
end
This is the gem I'm using https://github.com/mlanett/redis-lock 这是我正在使用的宝石https://github.com/mlanett/redis-lock
Here's what I'd do: 这是我要做的:
This will not prevent double submission, but at least will prevent the changes from second commit. 这不会阻止双重提交,但至少会阻止第二次提交的更改。 Ie when user submits the form second time the code will check the submitted token against the one in database and if they do not match - do not do an update to the object. 即,当用户第二次提交表单时,代码将检查提交的令牌与数据库中的令牌,如果它们不匹配 - 请勿对对象进行更新。
This also has a draw back for newly created objects (ie if user want's to create a comment or smth like that). 这也为新创建的对象提供了一个缺点(即,如果用户想要创建注释或类似的smth)。 But in this case you may want to check the creation time interval from same user and if it's less than, say, 5 seconds - you'd prevent the object from being "created". 但在这种情况下,您可能需要检查来自同一用户的创建时间间隔,如果它小于,比如5秒 - 您将阻止该对象被“创建”。
Not a real suggestion (I won't be surprised of downvotes), but will your site still be usable without JS? 不是真正的建议(我不会对downvotes感到惊讶),但是你的网站在没有JS的情况下仍然可用吗? How about showing him appropriate message that for normal operation he needs to enable the JS, otherwise you won't show him lots and lots of forms on the page. 如何向他展示适当的消息,正常操作需要启用JS,否则你不会在页面上显示很多很多表格。
1) It's nice to also show some moving indicator to let user know that something's going on, that their request is being processed. 1)很高兴也展示一些移动指示器,让用户知道正在发生的事情,他们的请求正在处理中。 It should eliminate lots of double submits. 它应该消除许多双重提交。
2) If user has disabled javascript, how're you gonna submit 'ajaxified' forms? 2)如果用户已禁用javascript,您将如何提交“ajaxified”表单? If site becomes not functional without javascript, then it's probably best to just notify user (like Eimantas suggests). 如果站点在没有javascript的情况下变得不起作用,那么最好只是通知用户(就像Eimantas建议的那样)。
edit One example of such indicator, just to be clear what I mean in 1. 编辑这种指标的一个例子,只是为了清楚我在1中的意思。
http://www.netzgesta.de/busy/ http://www.netzgesta.de/busy/
Not sure if this is helpful: 不确定这是否有用:
ON SERVERSIDE: 在服务器上:
On fresh load of the form, set a session['variable']=false //meaning the form isn't submitted yet. 在表单的新加载时,设置会话['variable'] = false //意味着表单尚未提交。
On form submit, check: 在表单提交上,检查:
if session['variable'] == true { do nothing... } else { set session['variable'] = true; //do submit logic here }
I happen to face the same problem as well, and I have solved it with a very simple way(maybe it is not proper or it exists something buggy I didn't notice, please inform me if you found out) 我碰巧也遇到了同样的问题,我用一种非常简单的方式解决了它(也许它是不正确的,或者它存在一些我没注意到的错误,如果你发现了,请通知我)
Here is my answer: 这是我的答案:
$submitButton.on('click', function(e) {
setTimeout(() => {
$(this).attr('disabled', '');
}, 0);
});
The main issue I was facing was that if I double clicked my original button, it would submit request twice and caused something unpredictable, so I tried to block the button with "disabled"attribute right after clicking it. 我面临的主要问题是,如果我双击原始按钮,它会提交两次请求并导致不可预测的内容,因此我尝试在单击后立即阻止具有“禁用”属性的按钮。 Here is what I wrote. 这是我写的。
// !!this is an incorrect example!!
$submitButton.on('click', function(e) {
$(this).attr('disabled', '');
});
// !!don't copy this!!
The biggest problem I was facing is that if I just disable the submit button right after clicking it, the submit request won't submit and the page will just hang there, as nothing ever happens. 我遇到的最大问题是,如果我只是在点击后立即禁用提交按钮,提交请求将不会提交,页面将只挂在那里,因为什么也没发生。
I think the cause is that the "disabled" attribute prevents the submit request from submitting.(Although I have no clue what the relationship between these two...) 我认为原因是“禁用”属性阻止了提交请求的提交。(虽然我不知道这两者之间的关系是什么......)
So, I think the disable event should be executed after submit event. 所以,我认为应该在提交事件后执行disable事件。
As far as I understand, form submitting is a Javascript event, and setTimeout is an async method. 据我所知,表单提交是一个Javascript事件,而setTimeout是一个异步方法。 As Javascript executes based on event loop , the ajax event will be put in the end of the event quene, and will be executed only after all the sync events finish. 当Javascript基于事件循环执行时,ajax事件将放在事件quene的末尾,并且只有在所有同步事件完成后才会执行。
In my code, after the first click, the submit button will be disabled after 0 millisecond, which is impossible for human beings to click the second time, problem solved! 在我的代码中,第一次点击后,提交按钮将在0毫秒后被禁用,这对于人类第二次点击是不可能的,问题解决了!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.