10

Bueno, todo está en el título, pero voy a explicar un poco más :-)En los controladores de rieles, ¿cómo evitar el envío doble (cuando el usuario hace doble clic en el botón de envío o presiona intro dos veces)?

Mi carriles de aplicación incluye muchas formas (Ajaxified o no).

Para evitar que los usuarios envíen dos o más formularios, utilizo Javascript.

Ahí está mi escenario para una forma Ajaxified:

  • el usuario envía el formulario (click o enter)
  • las javascript desactivar el botón de enviar
  • el controlador rieles hacer cosas (como una solicitud de jabón o una inserción en un DB)
  • la actualización del controlador rieles la página y permitir que el botón de enviar, si es necesario (en caso de errores)

Ahora Quiero agregar el código del lado del servidor para mantener las cosas realmente limpias si el usuario omite el javascript.

¿Alguna sugerencia?

Respuesta

5

Intente utilizar Redis bloqueo y rodear su bloque con algo así como

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

Esta es la joya que estoy usando https://github.com/mlanett/redis-lock

+1

Oye, esta es una publicación anterior, pero gracias por la respuesta de todos modos. Realmente me gusta este enfoque con el bloqueo de Redis. –

1

No es una sugerencia real (no me sorprenderán los votos a la baja), pero ¿su sitio seguirá siendo utilizable sin JS? ¿Qué le parece mostrarle el mensaje apropiado de que para una operación normal necesita habilitar el JS, de lo contrario no le mostrará muchos formularios en la página.

+0

Es cierto y me has hecho editar mi pregunta :-) El caso del usuario del que hablo es cuando el usuario omite el javascript. Considere que javascript siempre está activo. Mi pregunta es principalmente sobre la parte del servidor ... –

0

1) También es bueno mostrar algún indicador en movimiento para que el usuario sepa que algo está sucediendo, que su solicitud está siendo procesada. Debe eliminar muchos envíos dobles.

2) Si el usuario ha desactivado javascript, ¿cómo va a enviar formularios 'ajaxified'? Si el sitio deja de ser funcional sin javascript, entonces probablemente sea mejor simplemente notificar al usuario (como sugiere Eimantas).

edición Un ejemplo de dicho indicador, para ser claro lo que quiero decir en 1.
http://www.netzgesta.de/busy/

+0

1) Claro, implementaré una 2) He editado mi pregunta: el verdadero problema es si el usuario omite el javascript. (Si el usuario deshabilita el javascript, el envío del formulario se procesa de la forma habitual ... no es necesario evitar el envío doble) –

2

Esto es lo que haría:

  1. añadir un campo "token" a un objeto en db que está a punto de cambiarse.
  2. Ponga esa ficha en una forma que modifique dicho objeto.
  3. Inmediatamente después de la modificación guarde ese objeto con el token NUEVO.
  4. Use ese token en otras páginas visitadas.

Esto no evitará el doble envío, pero al menos evitará los cambios de la segunda confirmación. Es decir. cuando el usuario envía el formulario por segunda vez, el código verificará el token enviado contra el de la base de datos y, si no coinciden, no hará una actualización del objeto.

Esto también tiene un inconveniente para los objetos recién creados (es decir, si el usuario quiere crear un comentario o algo así).Pero en este caso es posible que desee comprobar el intervalo de tiempo de creación del mismo usuario y, si es inferior a, por ejemplo, 5 segundos, evitará que el objeto se "cree".

+0

Sí, también es una buena forma de manejar entradas múltiples. –

+0

Este enfoque de solicitudes de etiquetado es análogo al de etiquetar mensajes en RMI/RPC, que es esencialmente lo mismo. También es posible etiquetar a un grano más fino, como por modelo u objeto, y observar cómo reacciona el controlador ante los duplicados (por ejemplo, omita la operación de la base de datos pero aún así muestre la nueva página; el usuario no necesita saber algo salió mal). – nruth

0

No estoy seguro si esto es útil:

EN ServerSide:

  1. En la carga fresca de la forma, establecer una sesión [ 'variable'] = false // es decir, la forma ISN' t enviado aún

  2. El envío de formulario, marque:

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

¿Cómo evita esto enviar dos veces?Si un usuario hace clic en el botón de enviar dos veces rápidamente (por lo que la primera solicitud aún no ha llegado al back-end), la segunda entrega aún tendrá la sesión ['variable'] = false. –

7

Usted puede añadir la opción: disable_with => "Por favor, espere ..." a la etiqueta de envío.

+0

Característica del lado del cliente, no es lo que estaba buscando. De todos modos, la sugerencia es útil en otros casos. –

+1

cuidado. No es imposible evitar enviar solo con esto. Todavía no estoy seguro de qué desencadenó este error para algunos usuarios, solo que algo lo hizo. – Ricky

+0

Creo que esto está obsoleto en Rails 4: http://stackoverflow.com/a/9572893/1945948. –

6

utilizo 4 método para 4 escenarios, por favor prefiere en primer lugar mi awnser aquí : Prevent double submits in a Rails AJAX form

única limitación para los usuarios, haga clic en:

stopImmedia uso tePropagation y agrega un evento click al dom 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; 
     } 
    }); 
    }; 

límite de la presentar como AJAX: beforeSend attribut

uso de ajax.

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

sólo para el formato:

<%= f.submit "Save annotation", :disable_with => "Saving...", :class => "btn btn-primary", :id => "annotation-submit-button" %> 

o: desactivar: 仅仅 对 表单 元素, 按钮 等 起作用, 会 otros 阻止 其 上 的 事件 触发

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

:

Esta es la gema: https://github.com/mlanett/redis-lock

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

Buen resumen de las diferentes soluciones cliente y servidor. Tal vez las partes chinas puedan ser traducidas. :-) –

Cuestiones relacionadas