Disabilitare funzione "aggiorna" del browser

Salve a tutti.

Avrei un problemino.

Ho fatto una form con form_tag dove l’utente carica dei dati e poi
facendo click sul pulsante di submit questi vengono salvati in un
database.
Dopodichè viene presentata immediatamente una nuova form per caricare
altri dati.

Il mio problema è questo:

se a questo punto l’utente fa click sul pulsante “aggiorna” (o
“ricarica”) del browser questo ritrasmette i dati inviati l’ultima
volta, che nel mio caso significa aggiungere un altro record uguale a
quello appena inserito.

C’è un modo per evitare che questo accada?

Grazie a tutti

Ritorna sulla pagina con un redirect.

metti un controllo sul sistema che salva in modo da non creare dati
doppi

Paolo M. wrote:

Alessandro S. wrote:

metti un controllo sul sistema che salva in modo da non creare dati
doppi

Questa probabilmente è la soluzione migliore
-cut-

Grazie a tutti.

Purtroppo questa soluzione non è percorribile, perchè la tabella del
database è uno storico di movimentazione, quindi ci possono ben essere
due record identici uno sotto l’altro.

Non posso nemmeno utilizzare la soluzione del redirect, perchè devo
mostrare i risultati dell’inserimento precedente.

In pratica funziona cosi:

l’utente spara il codice a barre
si apre una pagina con la decodifica e i dati appena aggiunti alla
tabella
in questa pagina oltre alla decodifica c’è una form con il nuovo codice
a barre da sparare
l’utente spara nuovamente un codice a barre ed esce la pagina come sopra
se invece fa aggiorna manda un’altra volta il codice a barre di prima e
viene aggiunto di nuovo il codice di prima. Non posso bloccarlo perchè
potrebbe invece sparare due volte lo stesso codice a barre (non è detto
che sia un errore)

Grazie a tutti

On 3/8/09 10:10 PM, Sam P. wrote:

Grazie a tutti.

Purtroppo questa soluzione non è percorribile, perchè la tabella del
database è uno storico di movimentazione, quindi ci possono ben essere
due record identici uno sotto l’altro.

Non posso nemmeno utilizzare la soluzione del redirect, perchè devo
mostrare i risultati dell’inserimento precedente.

Ma nel redirect puoi sempre mandare l’id del record inserito e
rileggerlo dal FB; oppure usare la sessione; o un flash (che è sempre la
sessione)…

Oppure puoi usare protect_from_forgery e gestire l’exception
ActionController::InvalidAuthenticityToken che ti arriva al reload.
Controlla la documentazione, è abbastanza chiara.

Ciao,
Andrea

Altrimenti hai sempre l’opzione di mandare la form con ajax, in questo
caso aggiungi un parametro e non salvi se non lo ricevi

Alessandro S. wrote:

metti un controllo sul sistema che salva in modo da non creare dati
doppi

Questa probabilmente è la soluzione migliore perché ti cautela dalla
creazione di record doppi non solo in questo, ma anche in tutti gli
altri casi possibili. Puoi farlo impostando una unique key nel db sui
campi che devono essere univoci e per dare un messaggio all’utente ti
basta gestire in Rails l’eccezione che sarà ritornata dalla save. In
questo modo devi scrivere pochissimo codice in più e fai fare al db il
lavoro per cui è stato progettato. E’ molto DRY, no? :slight_smile:

Paolo

Andrea C. wrote:
-cut-

Ma nel redirect puoi sempre mandare l’id del record inserito e
rileggerlo dal FB; oppure usare la sessione; o un flash (che � sempre la
sessione)…

Grazie!
Alla fine ho fatto così.
Invece di fare il render di un partial dove mostravo i dati del record
appena creato ho fatto il redirect a un’altra azione passandogli l’id
del record creato. L’id l’ho messo in session perchè se uso params
ancora una volta l’utente lo puo’ cambiare dalla barra dell’indirizzo.
L’unica cosa che non mi piace è fare un accesso al DB che potevo
evitare, ma penso non ci sia altra soluzione.

Oppure puoi usare protect_from_forgery e gestire l’exception
ActionController::InvalidAuthenticityToken che ti arriva al reload.
Controlla la documentazione, � abbastanza chiara.

Questo invece non l’ho capito.
Allora, nel controller ho messo:

protect_from_forgery :secret => ‘segreta’

e nella view:

<%= javascript_tag “window._token = ‘#{form_authenticity_token}’” %>

Alla fine pero’ tutto funziona come a prima. Se faccio il reload dal
browser mi aggiunge un altro record e non mi arriva nessuna exception.

Tanto per capire, perchè ormai ho risolto nell’altro modo.

Grazie.

Oppure puoi disabilitare il pulsante di submit (si può da html?) ed
abilitarlo da javascript qualche secondo dopo il caricamento della
pagina. E’ un truccaccio ma dovrebbe funzionare.

Se input type=“submit” non avesse un disabled=“disabled” (non ho
controllato) puoi semplicemente non metterlo nel form e crearlo da
javascript.

adesso dico la mia… sperando che ti piacia.
aggiungi un campo timestamp nel db e lo rendi univoco. se fa una reload
trova il record doppio. Considerando che il timestamp ha, come standard,
il nano secondo, ho hai migliaia di accessi al minuto oppure è
impossibile duplicarlo.
Altra soluzione (non ho idea di come realizzarla) è aprendo un frame e
dando l’ok, viene inserito il record e il frame viene chiuso.

Ciao Michele.

On 3/10/09 5:17 PM, Sam P. wrote:

Invece di fare il render di un partial dove mostravo i dati del record
appena creato ho fatto il redirect a un’altra azione passandogli l’id
del record creato. L’id l’ho messo in session perchè se uso params
ancora una volta l’utente lo puo’ cambiare dalla barra dell’indirizzo.
L’unica cosa che non mi piace è fare un accesso al DB che potevo
evitare, ma penso non ci sia altra soluzione.

Ottimo. Evitare l’accesso al DB sarebbe un’ottima cosa, ma a meno che la
tua applicazione sia ad alto volume, non me ne preoccuperei troppo.
Vale sempre la regola d’ora: prima fallo funzionare bene, dopo pensa ad
ottimizzare :wink:

e nella view:

<%= javascript_tag “window._token = ‘#{form_authenticity_token}’” %>

Alla fine pero’ tutto funziona come a prima. Se faccio il reload dal
browser mi aggiunge un altro record e non mi arriva nessuna exception.

Tanto per capire, perchè ormai ho risolto nell’altro modo.

Non riesco a farti ora un esempio concreto, ma se crei una action
semplice non Ajax, con una form creata con form_for (e con
protect_from_forgery nel controller) dovresti vedere questo
comportamento:

  • nella form viene inserito un campo hidden con un token casuale
  • al submit della form, il controller verifica che quel token non sia
    già stato creato (dovresti vederti il token tra i parametri in
    development.log)
  • poi tu mostri il risultato della form; se l’utente fa reload,
    vengono rimandati gli stessi dati, incluso lo stesso token; il server ti
    tira una exception.

Non so perché tu non veda questa exception; di certo settare il token
via javascript non basta, la documentazione fornisce quell’esempio per
farti vedere come gestire questa cosa se ti crei del javascript a mano,
ma per un uso normale basta form_for / form_tag. Giocaci un po’ se hai
tempo e vuoi capire.

Naturalmente poi hai il problema di gestire l’exception, ad esempio con
rescue_action_in_public.

Ciao,
Andrea

Gino Ma wrote:
-cut-

La mia è questa,

session[:transazione] = 'on' in entrata new
if session[:transazione] == 'off' in entrata create

session[:transazione] = 'off'

dopo il create

Non funziona, e’ la prima cosa che ho fatto.
Quando facevo il reload in params mi ritrovavo anche lo stato di
session[:transazione] impostato per far creare il record.

Michele C. wrote:

adesso dico la mia… sperando che ti piacia.
aggiungi un campo timestamp nel db e lo rendi univoco. se fa una reload
trova il record doppio. Considerando che il timestamp ha, come standard,
il nano secondo, ho hai migliaia di accessi al minuto oppure è
impossibile duplicarlo.
Altra soluzione (non ho idea di come realizzarla) è aprendo un frame e
dando l’ok, viene inserito il record e il frame viene chiuso.

Ciao Michele.

La mia è questa,

session[:transazione] = 'on' in entrata new
if session[:transazione] == 'off' in entrata create

session[:transazione] = 'off'

dopo il create

Sam P. wrote:

Non funziona, e’ la prima cosa che ho fatto.
Quando facevo il reload in params mi ritrovavo anche lo stato di
session[:transazione] impostato per far creare il record.

a me funziona su 5 applicazioni in produzione.

Ciao

Gino Ma wrote:

Sam P. wrote:

Non funziona, e’ la prima cosa che ho fatto.

Ho controllato: questo risolve il tasto indietro del browser e il nuovo
invio…

se si esegue il reload dopo il tasto indietro allora controllo che la
registrazione non sia duplicata.

ciao