Подтвердить что ты не робот

В контроллерах rails, как предотвратить двойную отправку (когда пользовательская кнопка двойного клика или нажмите дважды)?

Ну, все в заголовке, но я объясню немного больше: -)

В моем приложении rails есть много форм (Ajaxified или нет).

Чтобы пользователи не отправляли два или более некоторых формы, я использую Javascript.

Там мой сценарий для Ajaxified формы:

  • пользователь отправляет форму (clic или enter)
  • javascript отключает кнопку отправки
  • контроллер rails делает что-то (например, запрос Soap или вставка в БД)
  • контроллер rails обновляет страницу и при необходимости активирует кнопку отправки (в случае ошибок)

Теперь Я хочу добавить код на стороне сервера, чтобы он был действительно чистым, если пользователь обошел javascript.

Любые предложения?

4b9b3361

Ответ 1

Попробуйте использовать блокировку Redis и окружайте свой блок чем-то вроде

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

Это драгоценный камень, который я использую https://github.com/mlanett/redis-lock

Ответ 2

Вы можете добавить параметр: disable_with = > "Подождите..." в тег submit.

Ответ 3

Я использую 4 метода для 4 сценариев, прежде всего, предпочитаю мой тэнер здесь: Предотвращать двойные отправки в форме AJAX Rails

ограничение только для пользователей:

используйте 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.

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

Ответ 4

Вот что я сделал бы:

  • Добавить поле "токенов" в объект в db, который будет изменен.
  • Поместите этот токен в форму, которая модифицирует указанный объект.
  • Сразу после модификации сохраните этот объект с новым токеном.
  • Используйте этот токен в других просмотрах страниц.

Это не будет препятствовать двойному представлению, но, по крайней мере, предотвратит изменения со второго фиксации. То есть когда пользователь отправляет форму во второй раз, код проверяет поданный токен на тот, что находится в базе данных, и если они не совпадают - не делайте обновления для объекта.

Это также имеет откат для вновь созданных объектов (т.е. если пользователь хочет создать комментарий или smth, как это). Но в этом случае вы можете проверить временной интервал создания от того же пользователя, и если он меньше, скажем, 5 секунд, вы не позволили бы "создать" объект.

Ответ 5

Не настоящее предложение (я не удивлюсь нисходящим), но будет ли ваш сайт по-прежнему использоваться без JS? Как насчет того, чтобы показать ему соответствующее сообщение, что для нормальной работы ему нужно включить JS, иначе вы не будете показывать ему много и много форм на странице.

Ответ 6

1) Приятно также показать некоторый движущийся индикатор, чтобы пользователь знал, что что-то происходит, что их запрос обрабатывается. Он должен устранить множество двойных представлений.

2) Если пользователь отключил javascript, как вы собираетесь отправлять 'ajaxified' формы? Если сайт становится недействительным без javascript, то, вероятно, лучше всего просто уведомить пользователя (например, Eimantas).

изменить Один пример такого показателя, просто чтобы понять, что я имею в виду в 1.
http://www.netzgesta.de/busy/

Ответ 7

Не уверен, что это полезно:

ПО СЕРВЕРУ:

  • При новой загрузке формы, установить сеанс ['variable'] = false//означает, что форма еще не отправлена.

  • В форме submit проверьте:

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