Guida Ruby on Rails: convalida e test

Nel corso del precedente articolo abbiamo finalmente creato l’applicazione che ci accompagnerà per tutto il resto della guida. Nello specifico, abbiamo associato un database all’applicazione, generato il primo scaffold, utilizzato il comando rake per controllare una migration e, infine, abbiamo modificato le prime views

Oggi ci occuperemo, invece, di accertarci che non vengano passati dati errati al nostro database. Ad esempio, sarebbe illogico accettare come valore del campo price una stringa di testo, così come sarebbe inutile consentire di lasciar vuoto il campo title o quello description.

Convalidiamo i campi

Il controllo di cui abbiamo discusso poc’anzi deve avvenire all’interno del model, come la logica del triumvirato MVC impone. Apriamo, quindi, il file app/models/books.rb; ci apparirà piuttosto vuoto:

    class Book < ActiveRecord::Base
    end

Diamoci da fare e rendiamolo utile!

Il primo passo è quello di accertarci che tutti i campi necessari contengano effettivamente un valore e non siano vuoti. Per fare ciò, ci basterà utilizzare il metodo validates che si occuperà di controllare uno o più campi a confronto di una o più condizioni. Nel nostro caso scriveremo:

    validates :title, :description, :image, presence: true

dove i campi da controllare sono title, description e image, mentre la condizione è, come facilmente si può intuire, rappresentata dal valore true di presence.

Proviamo adesso a creare un nuovo libro senza rispettare i parametri appena imposti. Ciò che apparirà ai nostri occhi sarà:

rubyconvalida1

Come puoi notare, manca il controllo sul campo price. Questo perché non solo ci interessa controllare che il campo sia effettivamente compilato, ma anche che sia un valore numerico e soprattutto che sia maggiore di 0. Per far ciò la condizione da rispettare dev’essere:

    validates :price, numericality: {greater_than_or_equal_to: 0.01}

che, in caso di errore, restituirà:

rubyconvalida2

Non ci resta che accertarci di soddisfare ulteriori due condizioni: il campo title non deve risultare un duplicato e il campo image deve contenere l’estensione jpg, png o gif.

Per controllare la prima di queste due condizioni, basta ricorrere alla condizione uniqueness in questo modo:

    validates :title, uniqueness: true

La seconda, invece, richiede un meccanismo leggermente più complesso per funzionare a dovere: l’utilizzo di una regular expression. Nello specifico dobbiamo essere sicuri che, nel campo image, sia presente almeno un carattere seguito da un estensione .jpg, .png o .gif. Il codice da scrivere risulterà, quindi:

    validates :image, allow_blank: true, format: {
        with: %r{\w.(jpg|png|gif)\Z}i,
        message: 'image must be a jpg, png or a gif file'
    }

Prima di proseguire nella spiegazione è necessario aprire una breve parentesi. Le regular expression sono un argomento complesso e, in questo caso, mi sono limitato ad utilizzarne una che, seppur non completamente efficace, può essere facilmente spiegata a un pubblico nuovo all’argomento. Se vuoi approfondire questo aspetto, qui puoi trovare una guida più esaustiva.

Model test

Una volta conclusa la fase della validazione, possiamo passare a quella più complessa del test. Occupiamoci, quindi, di testare il model che ci interessa aprendo test/models/book_test.rb e aggiungendo:

    test "book attributes must not be empty" do
        book = Book.new
        assert book.invalid?
        assert book.errors[:title].any?
        assert book.errors[:description].any?
        assert book.errors[:price].any?
        assert book.errors[:image].any?
    end

È facile intuire come il metodo assert restituisca true se la condizione è soddisfatta e false se la condizione non è soddisfatta. Con il codice appena creato abbiamo controllato che, aggiungendo un nuovo libro privo dei campi che abbiamo reso obbligatori, vengano restituiti i corrispondenti errori. Adesso, digitando da terminale rake test:models, avremo un output del genere:

rubyconvalida3

Allo stesso modo testiamo il meccanismo riguardante il prezzo.

    test "book price must be positive" do
        book = Book.new(title: "Title 1",
                      description: "description test", 
                      image: "test.jpg")
        book.price = -1
        assert book.invalid?
        assert_equal ["must be greater than or equal to 0.01"], book.errors[:price]
        book.price = 0
        assert book.invalid?
        assert_equal ["must be greater than or equal to 0.01"], book.errors[:price]
        book.price = 1
        assert book.valid?
    end

e quello relativo all’estensione delle immagini.

def new_book(image) 
        Book.new(title: "Title 1",
                description: "description test", 
                price: 1, 
                image: image)
    end
    test "image" do
        ok = %w{test.gif test.jpg test.png TEST.JPG TEST.Jpg http://p.r.o/v/a/test.png}
        bad = %w{ test.doc test.png/more test.jpg.more } 
        ok.each do |name|
            assert new_book(name).valid?, "#{name} should be valid"
        end
        bad.each do |name|
            assert new_book(name).invalid?, "#{name} shouldn't be valid"
        end
    end

Conclusioni

Nel corso di questa guida torneremo più volte sul tema dei test poiché, come hai potuto capire, è un meccanismo fondamentale per assicurarci, passo dopo passo, di non tralasciare o sbagliare nulla. Nonostante ciò, se vuoi approfondire il testing prima del tempo, ti consiglio di far riferimento alla guida che trovi sul sito ufficiale. Nel prossimo articolo torneremo a sviluppare nuove funzioni per la nostra app; in particolare, aggiungeremo un carrello!

Prima di concludere, puoi scaricare il codice completo dell’app da questo indirizzo.

GUIDA RUBY ON RAILS: INDICE LEZIONI
1) Introduzione
2) L’ambiente di lavoro e la nostra prima app
3) Un assaggio di dinamicità
4) Architettura di un’applicazione
5) Il linguaggio Ruby – Parte 1
6) Il linguaggio Ruby – Parte 2
7) Creiamo c-Bookcase
8) Convalida e test
9) Ruby on Rails: page layout
10) Guida Ruby on Rails: creiamo il carrello

Tag: , , ,

L'autore

Da sempre appassionato di nuove tecnologie, guadagno il pane quotidiano scrivendo fiumi di funzioni, tonnellate di script, sciami di variabili: insomma un infinità di codice! Amante dei viaggi e del viaggio, scompongo le mie esperienze lontano da casa in complesse logiche procedurali e in stupendi design. Ancora in cerca del tag giusto per descrivere la mia vita.

Altri articoli scritti da

Articoli correlati

Potresti essere interessato anche ai seguenti articoli:

Lascia un Commento