14

好吧,一切都在标题中,但我会解释更多:-)

我的 rails 应用程序包含许多表单(Ajaxified 与否)。

为了防止用户提交两次或更多的某些表单,我使用了 Javascript。

我有一个 Ajaxified 表单的场景:

  • 用户提交表单(单击或输入)
  • javascript禁用提交按钮
  • rails 控制器做一些事情(比如一个肥皂请求或一个数据库中的插入)
  • rails 控制器更新页面并在必要时启用提交按钮(以防出错)

现在我想添加服务器端代码,以在用户绕过 javascript 时保持干净。

有什么建议么?

4

8 回答 8

9

您可以将选项 :disable_with => "Please Wait..." 添加到提交标签。

于 2012-07-17T13:15:15.497 回答
9

我在 4 种情况下使用 4 种方法,请先在这里使用我的 awnser:Prevent double submits in a Rails AJAX form

用户只点击限制:

使用 stopImmediatePropagation 并向目标 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;
      }
    });
  };

限制提交如ajax:

使用 ajax 的 beforeSend 属性。

  /**
   * 使用:
   *   在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" %>

或者:禁用:对表单元素,按钮等,会阻止上的事件触发

<input type="submit" value="submit" />
<input type="button" value="button" />
<input type="image" value="image" />

其他:

这是宝石:<a href="https://github.com/mlanett/redis-lock" rel="nofollow noreferrer">https://github.com/mlanett/redis-lock

Redis.current.lock("#{current_user.id}.action_name") do
   # Some code
end
于 2013-11-23T11:57:29.433 回答
8

尝试使用 Redis 锁定并用类似的东西包围你的块

Redis.current.lock("#{current_user.id}.action_name") do
   # Some code
end

这是我正在使用的宝石 https://github.com/mlanett/redis-lock

于 2013-02-19T20:30:41.067 回答
2

这是我要做的:

  1. 将“令牌”字段添加到数据库中即将更改的对象。
  2. 将该标记放入修改所述对象的形式中。
  3. 修改后立即使用新令牌保存该对象。
  4. 在其他页面视图中使用该令牌。

这不会阻止重复提交,但至少会阻止第二次提交的更改。即,当用户第二次提交表单时,代码将根据数据库中的令牌检查提交的令牌,如果它们不匹配 - 不要更新对象。

这对新创建的对象也有不利影响(即,如果用户想要创建评论或类似的东西)。但在这种情况下,您可能想要检查来自同一用户的创建时间间隔,如果它小于 5 秒 - 您将阻止对象被“创建”。

于 2010-07-05T08:29:20.433 回答
1

不是一个真正的建议(我不会对不赞成票感到惊讶),但是您的网站在没有 JS 的情况下仍然可以使用吗?向他显示适当的消息如何正常操作他需要启用 JS,否则您不会在页面上向他显示大量的表单。

于 2010-07-01T17:32:52.667 回答
0

1) 还可以显示一些移动指示器,让用户知道正在发生的事情,他们的请求正在处理中,这很好。它应该消除大量的双重提交。

2)如果用户禁用了javascript,你将如何提交“ajaxified”表单?如果网站在没有 javascript 的情况下无法运行,那么最好只通知用户(就像Eimantas建议的那样)。

编辑 此类指标的一个示例,只是为了清楚我在 1 中的意思。
http://www.netzgesta.de/busy/

于 2010-07-01T17:39:36.967 回答
0

不确定这是否有帮助:

在服务器端:

  1. 在新加载表单时,设置 session['variable']=false //表示表单尚未提交。

  2. 在表单提交时,检查:

    if session['variable'] == true
    {
       do nothing...
    }
    else
    {
       set session['variable'] = true;
      //do submit logic here
    }
    
于 2010-07-05T09:01:54.617 回答
0

我碰巧也遇到了同样的问题,我已经用一个非常简单的方法解决了(可能是不合适的或者它存在一些我没有注意到的错误,如果你发现了请告诉我)

这是我的答案:

$submitButton.on('click', function(e) {
  setTimeout(() => {
    $(this).attr('disabled', '');
  }, 0);
});

我面临的主要问题是,如果我双击原始按钮,它会提交两次请求并导致不可预知的事情,所以我试图在单击后立即阻止具有“禁用”属性的按钮。这是我写的。

// !!this is an incorrect example!!
$submitButton.on('click', function(e) {
    $(this).attr('disabled', '');
});
// !!don't copy this!!

我面临的最大问题是,如果我只是在单击提交按钮后立即禁用它,则提交请求将不会提交,并且页面只会挂在那里,因为什么都没有发生。

我认为原因是“禁用”属性阻止提交请求提交。(虽然我不知道这两者之间的关系是什么......)

所以,我认为禁用事件应该在提交事件之后执行。

据我了解,表单提交是一个 Javascript 事件,而 setTimeout 是一个异步方法。由于 Javascript 基于事件循环执行,ajax 事件将放在事件队列的末尾,并且只有在所有同步事件完成后才会执行。

在我的代码中,第一次点击后,提交按钮会在0毫秒后被禁用,这是人类不可能第二次点击的,问题解决了!

于 2018-05-15T14:37:40.917 回答