簡體   English   中英

在rails控制器中,如何防止雙重提交(當用戶雙提交按鈕或按兩次輸入時)?

[英]In rails controllers, how to prevent double submit (when user double-clic submit button or hit enter twice)?

好吧,一切都在標題中,但我會解釋一下:-)

我的rails應用程序包含許多表單(Ajaxified或不Ajaxified)。

為了防止用戶提交兩次或更多的表格,我使用Javascript。

有一個Ajaxified表單的場景:

  • 用戶提交表格(clic或enter)
  • javascript禁用提交按鈕
  • rails控制器執行操作(如Soap請求或DB中的插入)
  • rails控制器更新頁面並在必要時啟用提交按鈕(如果有錯誤)

現在我想添加服務器端代碼,以便在用戶繞過javascript時保持真正干凈。

有什么建議?

我在4個場景中使用4方法,請首先在這里選擇我的awnser: 防止在Rails AJAX表單中提交雙重提交

僅針對用戶的點擊限制:

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

限制提交,如ajax:

使用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" %>

或:禁用:僅僅對表單元素,按鈕等起作用,會阻止其上的事件觸發

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

其他:

這是寶石: https//github.com/mlanett/redis-lock

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

您可以在提交標記中添加選項:disable_with =>“Please Wait ...”。

嘗試使用Redis鎖定並用類似的東西包圍你的塊

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

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

這是我要做的:

  1. 將“標記”字段添加到即將更改的db中的對象。
  2. 將該標記放入修改所述對象的表單中。
  3. 修改后立即使用NEW令牌保存該對象。
  4. 在其他頁面視圖中使用該標記。

這不會阻止雙重提交,但至少會阻止第二次提交的更改。 即,當用戶第二次提交表單時,代碼將檢查提交的令牌與數據庫中的令牌,如果它們不匹配 - 請勿對對象進行更新。

這也為新創建的對象提供了一個缺點(即,如果用戶想要創建注釋或類似的smth)。 但在這種情況下,您可能需要檢查來自同一用戶的創建時間間隔,如果它小於,比如5秒 - 您將阻止該對象被“創建”。

不是真正的建議(我不會對downvotes感到驚訝),但是你的網站在沒有JS的情況下仍然可用嗎? 如何向他展示適當的消息,正常操作需要啟用JS,否則你不會在頁面上顯示很多很多表格。

1)很高興也展示一些移動指示器,讓用戶知道正在發生的事情,他們的請求正在處理中。 它應該消除許多雙重提交。

2)如果用戶已禁用javascript,您將如何提交“ajaxified”表單? 如果站點在沒有javascript的情況下變得不起作用,那么最好只是通知用戶(就像Eimantas建議的那樣)。

編輯這種指標的一個例子,只是為了清楚我在1中的意思。
http://www.netzgesta.de/busy/

不確定這是否有用:

在服務器上:

  1. 在表單的新加載時,設置會話['variable'] = false //意味着表單尚未提交。

  2. 在表單提交上,檢查:

     if session['variable'] == true { do nothing... } else { set session['variable'] = true; //do submit logic here } 

我碰巧也遇到了同樣的問題,我用一種非常簡單的方式解決了它(也許它是不正確的,或者它存在一些我沒注意到的錯誤,如果你發現了,請通知我)

這是我的答案:

$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!!

我遇到的最大問題是,如果我只是在點擊后立即禁用提交按鈕,提交請求將不會提交,頁面將只掛在那里,因為什么也沒發生。

我認為原因是“禁用”屬性阻止了提交請求的提交。(雖然我不知道這兩者之間的關系是什么......)

所以,我認為應該在提交事件后執行disable事件。

據我所知,表單提交是一個Javascript事件,而setTimeout是一個異步方法。 當Javascript基於事件循環執行時,ajax事件將放在事件quene的末尾,並且只有在所有同步事件完成后才會執行。

在我的代碼中,第一次點擊后,提交按鈕將在0毫秒后被禁用,這對於人類第二次點擊是不可能的,問題解決了!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM