简体   繁体   English

在rails控制器中,如何防止双重提交(当用户双提交按钮或按两次输入时)?

[英]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表单的场景:

  • the user submit the form (clic or enter) 用户提交表格(clic或enter)
  • the javascript disable the submit button javascript禁用提交按钮
  • the rails controller do things (like a Soap request or an insert in a DB) rails控制器执行操作(如Soap请求或DB中的插入)
  • the rails controller update the page and enable the submit button if necessary (in case of errors) rails控制器更新页面并在必要时启用提交按钮(如果有错误)

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表单中提交双重提交

only click limitation for users: 仅针对用户的点击限制:

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;
      }
    });
  };

limit the submit such as ajax: 限制提交,如ajax:

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;
    }
  };

only for form: 仅适用于表格:

<%= 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" />

others: 其他:

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: 这是我要做的:

  1. Add a "token" field to an object in db that's about to be changed. 将“标记”字段添加到即将更改的db中的对象。
  2. Put that token into a form that modifies said object. 将该标记放入修改所述对象的表单中。
  3. Right after modification save that object with NEW token. 修改后立即使用NEW令牌保存该对象。
  4. Use that token in other page views. 在其他页面视图中使用该标记。

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: 在服务器上:

  1. On fresh load of the form, set a session['variable']=false //meaning the form isn't submitted yet. 在表单的新加载时,设置会话['variable'] = false //意味着表单尚未提交。

  2. 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.

相关问题 当用户双击提交按钮时,需要避免向服务器提交两次表单 - Need to avoid submit form twice to the server when user double clicks on submit button 我的用户如何按 Enter 键或单击按钮提交并被重定向? - How can my user hit enter or click a button to submit and be redirected? 如何防止使用不同的按钮重用模式来防止表单的双重提交? - How to prevent a double submit of a form, reusing a modal with a different button? 防止双重提交 - Prevent double submit 如何通过表单验证防止双重提交 - How To Prevent Double Submit With Form Validation 如何防止双击提交表单? Javascript - How to prevent double click on the submit form? Javascript 当我单击提交按钮时,Rails 3.0:remote =&gt; true with ie9将使提交表单加倍 - Rails 3.0 :remote => true with ie9 will double submit form when I click on submit button 在提交时使用JavaScript禁用表单,以防止重复提交 - Disabling forms with javascript on submit to prevent double submit 两次提交,防止默认设置不起作用 - Double submit, prevent default not working 在单击按钮之前从其他控件执行回发时,防止双击提交按钮 - Prevent double click in submit-button when postback from other controls executed before button click
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM