Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Validazione dell'input

Come validare i dati inviati dagli utenti alle applicazioni scritte in Ruby on Rails
Come validare i dati inviati dagli utenti alle applicazioni scritte in Ruby on Rails
Link copiato negli appunti

Ma cosa fare se l'utente sbaglia ad inserire la password e la verifica fallisce? E se un autore con lo stesso nome esiste già? E se uno dei parametri non viene inserito? I problemi di validazione dell'input in Rails vengono gestiti sempre nel modello. In questo modo, le regole di validazione possono essere riutilizzate da ogni altro elemento dell'applicazione o anche essere riutilizzate in applicazioni differenti. 

Per far sì che la validazione sia la più semplice possibile ActiveRecord mette a disposizione differenti metodi speciali, simili a quel metodo scaffold già visto nei controller. In particolare, potremo cambiare il modello in app/models/author.rb in questo modo:

class Author < ActiveRecord::Base
 
    validates_presence_of :name, :password
    validates_uniqueness_of :name
    validates_confirmation_of :password
 
has_many :messages
end

Cosa significano quelle tre nuove linee? Semplicemente, la prima verifica che gli attributi password e name abbiano un valore. La seconda verifica che l'attributo name non sia già presente nel database, preoccupandosi di effettuare al posto nostro le operazioni in SQL. La terza verifica che password e password_confirmation siano uguali. Ancora una volta, ci basta seguire una piccola convenzione, ovvero chiamare i campi nome e nome_confirmation per far sì che Rails gestisca tutto automaticamente.  

Sebbene esistano molte di queste validazioni predefinite, che permettono ad esempio di verificare il formato o la lunghezza di un campo, di escludere alcuni valori predefiniti e persino di controllare che l'utente abbia accettato delle condizioni (come la classica check box per il trattamento dei dati personali) è comunque sempre possibile definire un metodo apposito, chiamato validate, che verrà eseguito per verificare regole più complesse, controllando il contenuto dell'oggetto, le sue relazioni ed applicando un controllo di qualunque altro tipo che non corrisponda a quelli disponibili. 

Provando a creare degli oggetti di tipo Author con script/console possiamo vedere cosa succede quando fallisce una validazione:

>> author=Author.new( :name=>"nome", :password=>"pass", :password_confirmation=>"sbagliata")
=> #<Author:0x3b8a1b8 @new_record=true, @attributes={"name"=>"nome", "password"=>"pass"}, @password_confirmation="sbagliata">
>> author.save
=> false

save restituisce false invece del solito true, ad indicare che in effetti l'oggetto non è stato salvato, perché qualcosa è andato male. Gli errori vengono salvati in un attributo speciale degli oggetti del modello, chiamato errors, e sono accessibili come coppie chiave/valore in questo modo:

>> for name, error in author.errors
>>  puts name+ ": "+ error
>> end
password: doesn't match confirmation

Avendo capito come accedere a queste informazioni, ci basterà riutilizzare l'oggetto nella vista, e mostrarne gli errori. Ma  ancora una volta, Rails fornisce già un meccanismo molto veloce per farlo, ovvero l'helper error_messages_for, che può essere usato in questo modo:

<%= error_messages_for "author" %>

Ovviamente, questo produce un codice standard (ed altrettanto standard messaggi di errore) che potrebbero non essere adeguati al nostro sistema, nel qual caso si potrà comunque gestirli da soli con l'approccio già visto (un'iterazione esplicita), o tramite gli altri metodi messi a disposizione dalla classe Errors. Notate che questo helper utilizza il nome di una variabile, e quindi nel metodo del controller sarà necessario utilizzare una variabile @author.

Notate che quando l'azione viene richiamata tramite un collegamento, cioè tramite GET, l'intero blocco if non viene eseguito, e quindi la variabile è vuota e nella pagina non viene mostrato nulla, esattamente il comportamento che desideriamo. 

La pagina di login sarà sostanzialmente identica, ma in questo caso possiamo rendere la vista ancora più semplice utilizzando un altro helper, chiamato semplicemente form . Questo helper prende in input il nome di una variabile d'istanza, come error_messages_for, poi la analizza per vedere quali sono i suoi attributi ed infine costruisce una form appropriata per i suoi campi. Ad esempio, per uno dei nostri oggetti di classe Author,  inserirà un form per la password ed uno per il nome.  form non ha difficoltà a gestire oggetti anche molto complessi,  anzi, più il modello è articolato tanto più è utile questo helper, che ci permette di creare una form per una tabella con una mezza dozzina di colonne in una sola riga di codice. 

Possiamo inoltre passare degli argomenti aggiuntivi, tra cui le specifiche di quale azione deve essere richiamata dal form, nel nostro caso, specificheremo di nuovo login. Il codice della vista in app/views/user/login.rhtml potrà essere dunque una cosa del genere:

<h1>Esegue il login</h1>

<%= @invalid_login_error %>
<%= form("author", :action=>'login') %>

Mentre il metodo definito in UserController, dentro app/controller/user_controller.rb sarà: 

def login
   @author=Author.new(params['author'])
   if request.post?
     if @author.valid_credentials?
       logged
     else
       @invalid_login_error="User o password errati"
     end
   end
end

abbiamo spostato la creazione dell'oggetto al di fuori dell'if, in quanto esso ci serve per l'helper form, in ogni caso.

All'interno del metodo poi, impostiamo una variabile d'errore se l'utente non inserisce dati corretti, e lo redirigiamo verso la home page se invece li ha inseriti correttamente. Il metodo valid_credentials? invece è un nuovo metodo, che definiremo nel modello per gli autori e cioè nel file app/model/author.rb, in questo modo: 

def valid_credentials?
   saved=Author.find_by_name(name)
   return (saved and (password == saved.password))
end

Ricordate che i vari metodi find restituiscono nil se non trovano un oggetto, e che nil è considerato un valore falso in Ruby. 

Ancora una volta, cercate di fare attenzione a dove abbiamo definito le varie funzionalità: capire se un utente è valido o meno è un compito del modello, e quindi abbiamo messo in quel punto la logica. Se un domani decidessimo di offrire la possibilità all'utenti di effettuare operazioni tramite Web service, potremmo riutilizzare questa parte di logica. 

Invece, sapere cosa fare con un utente che cerca di effettuare il login via web è compito del controller, e il fatto che questo codice non sia strettamente collegato alla vista fa sì che sia possibile riutilizzarlo ad esempio con una form che si trova in un'altra azione, ad esempio mettendo un box per il login nella homepage.


Ti consigliamo anche