2012-03-06 5 views
7

Nella mia app, ho a volte creare un utente al volo, e-mail di un utente deve essere un formato valido ed essere unicorotaie 3.1: come può App gestire diversi 'ragioni' per ActiveRecord :: RecordInvalid (ad esempio, duplicare vs errore di convalida)

Vorrei reindirizzare a luoghi diversi a seconda di quale convalida causato l'errore di essere sollevato: formato non valido vs duplicato.

Nel mio codice ho

begin 
     user.save! 
     flash[:notice] = "Created new user #{email} with password #{password}" 

    rescue ActiveRecord::RecordInvalid => e 
     flash[:alert] = "Failed to create account because #{e.message}" 
     redirect_to SOMEPLACE 
    end 

Se l'email è formato non valido (come "user @ example") e.Message è "Validazione fallita: La posta elettronica è valido"

Se l'e-mail esiste già nella tabella, e.message è "Convalida non riuscita: l'e-mail è già stata presa"

Odio l'idea di analizzare il testo e.message per determinare il motivo ... c'è un modo migliore per un gestore di salvataggio per rilevare il motivo sottostante un'eccezione ActiveRecord :: RecordInvalid w come gettato?

P.S. So che in questo esempio posso semplicemente controllare in anticipo l'e-mail già esistente prima di fare un salvataggio, ma sto cercando di capire la soluzione generale per rilevare e agire su diversi fallimenti di convalida generando la stessa eccezione.

+1

in realtà non può semplicemente controllare in anticipo per l'e-mail già esistente, convalide unicità di ActiveRecord sono soggetti a condizioni di gara e rotto in base alla progettazione. È necessario disporre di un vincolo di unicità all'interno del vostro database e devi essere preparato t o affrontare l'eccezione che solleverà (da '.save' o' .save! '). –

risposta

1

Il metodo standard Rails per fare questo è di non usare l'operatore botto, che solleva un'eccezione, ma di utilizzare lo standard Salva metodo e verificare se restituito vero o falso:

if @user.save 
    flash[:notice] = "User created." 
    redirect_to :action => :index 
else 
    flash[:alert] = "User could not be created." 
    render :action => :new 
end 

E nel tuo utente vista creazione:

<% if @user.errors.any? %> 
    <ul> 
    <% @user.errors.full_messages.each do |msg| %> 
     <li><%= msg %></li> 
    <% end %> 
    </ul> 
<% end %> 
+0

Ma questo non ti dice perché il salvataggio è fallito. Se si dispone di un vincolo univoco all'interno del database (che si dovrebbe come convalida l'unicità di AR è soggetta a condizioni di gara), allora si può avere 'x.valid?' Essere vero, ma sia x.save' e '' x.save! 'Can genera un'eccezione perché il vincolo del database è stato violato. –

0

Se sto capire che cosa si sta cercando di fare in modo corretto, un modo per farlo sarebbe quello di far valere solo contro la presenza di un errore nel livello di campo. per esempio.

if user.errors[:field_name].present? 
    redirect_to path_for_field_name_error 
end 

In alternativa, è possibile definire alcuni mappatura dei quali campi reindirizzare dove come una costante (ad es REDIRECT_PATHS nel qual caso si finisce con qualcosa di simile:

redirect_to REDIRECT_PATHS[field_name] if user.errors[:field_name].present? 

in cui si può solo ciclo nel corso degli field_name s .

+0

Nel mio esempio, potrebbero verificarsi più errori per lo stesso indirizzo di posta elettronica campo potrebbe essere non valido, o già utilizzato, per esempio. – jpwynn

+0

K. Se è possibile in qualche modo utilizzare le ActiveRecord built-in per gestire tutto ciò che non è questo vincolo di unicità DB-driven (che @mu è troppo breve rileva non funziona sempre come previsto correttamente), allora si potrebbe essere in grado di controllare solo contro '.valid?' e rimuovere gli errori in questo modo, ad eccezione di questo vincolo di unicità. Ovviamente, se si hanno più vincoli su altri campi, è ancora un problema e ricade sull'analisi delle stringhe. Buona fortuna, spero che sia utile? –

Problemi correlati