Ruby On Rails, noto anche attraverso l’acronimo RoR o con l’abbreviazione Rails, รจ un Web framework rilasciato sotto licenza Open Source (MIT License) e disponibile gratuitamente per il libero utilizzo; esso รจ stato realizzato in linguaggio Ruby con l’obiettivo di velocizzare il lavoro di sviluppo delle applicazioni mettendo a disposizione strutture e librerie pronte all’uso.
Uno dei principi cardine che su cui รจ stato basato il lavoro di realizzazione di RoR รจ relativo all’eliminazione delle ripetizioni (metodologia DRY, acronimo di “Do not Repeat Yourself“), per cui, una volta definito uno specifico elemento, tale operazione non dovrร essere eseguita una seconda volta; questa caratteristica diventa particolarmente interessante quando si ha la necessitร di riutilizzare porzioni di codice in diverse componenti progettuali o, addirittura, nella condivisione di tali frammenti di sorgente tra vari progetti.
Rails รจ un framework di tipo full-stack, ciรฒ significa che esso prevede un livello di integrazione tale fra i diversi componenti che non sarร necessario impostare manualmente i collegamenti tra di essi; in linea generale รจ possibile affermare che un framework full-stack viene concepito per coprire tutti i livelli di una Web application, dalla gestione della logica applicativa fino all’interazione con sorgenti esterne d’informazioni come per esempio le basi di dati.
RoR รจ stato concepito basandosi sull’architettura MVC (Model-View-Controller), una struttura progettuale, o “pattern”, appositamente pensata per fornire agli sviluppatori uno schema di tipo generale attraverso il quale risolvere razionalmente le problematiche ricorrenti nell’organizzazione di un’applicazione. Il pattern architetturale MVC consiste in pratica nel gestire in modo indipendente gli elementi (dati) associati alle funzionalitร (logica applicativa), da quelli legati alla presentazione (interfaccia utente) e dalle componenti che controllano e adottano le funzionalitร stesse (ancora logica applicativa). Nello specifico, il paradigma MVC prevede la presenza di:
- un Model (modello) che mette a disposizione i metodi attraverso i quali avere accesso alle informazioni manipolabili dall’applicazione;
- una View (vista) il cui compito รจ quello di rendere visibili le informazioni che fanno riferimento al modello e di consentire l’interazione con i dati; a partire dalla release numero 2, RoR supporta il MultivVew per la generazione di viste in formati diversi sulla base dal medesimo sorgente, per cui dallo stesso codice sarร possibile ottenere una View in HTML, una in XML, CSV e cosรฌ via (disponibile anche il supporto per il formato d’interscambio JSON);
- un Controller (controllo) il cui compito consiste nell’intercettare le istruzioni inviate tramite le Views alterando lo stato di modelli e viste.
In Rails il componente Model รจ gestito tramite un apposito modulo denominato ActiveRecords e utilizza una rappresentazione del dato legata al paradigma per oggetti definendone proprietร e relazioni, alle Views fa invece riferimento il modulo ActionView, mentre i Controller sono gestiti tramite modulo ActionController. Il ruolo di tali moduli verrร approfondito nel corso di questa trattazione facendo riferimento alla loro utilitร a livello pratico.
Un altro elemento caratterizzante di RoR sta nel fatto che esso รจ stato dotato di un’architettura basata su convenzioni (principio della Convention Over Configuration) per cui, dato un determinato modello che fa riferimento ad una classe, vi sarร sicuramente un elemento omonimo su cui tale classe andrร ad agire o con cui dovrร interagire; per operare al di fuori delle convenzioni, quindi in modo non previsto da queste ultime, sarร invece necessario operare in manualmente sulle configurazioni relative agli elementi che interagiscono con classi e modelli. ROR รจ inoltre multipiattaforma, ciรฒ significa che รจ in grado di funzionare dando luogo ai medesimi comportamenti e risultati indipendentemente dal sistema operativo di riferimento.
Nei prossimi capitoli verranno quindi analizzate le procedure necessarie per la creazione e l’inizializzazione di un ambiente operativo mirato alla realizzazione di un progetto Rails.
Indice
- Installazione di RoR su Windows
- Installazione di RoR su Linux
- Installazione di RoR su Mac Os X
- Inizializzazione dell’ambiente operativo
- RoR e database: installare MySQL
- Creiamo la nostra prima Web Application con RoR
- Generare codice con lo Scaffolding
- Creare tabelle con le migration
- Attivazione dell’applicazione e routing
- Validazione dei parametri e Rails console
- Views e personalizzazione del layout
- Il layout specifico per l’applicazione
- Riutilizzare codice con i partials
- Visualizzazione, aggiornamento e cancellazione dei record
- Introdurre un Model addizionale
- Routing, Controller e View del model addizionale
- Generazione manuale delle Views
- Autenticazione in Rails
Installazione di RoR su Windows
Per utilizzare RoR sui sistemi operativi della Casa di Redmond avrete bisogno innanzitutto di Ruby, infatti il framework lavora e funziona sulla base del linguaggio di programmazione e del suo ambiente; per Windows gli sviluppatori hanno messo a disposizione un apposito installer che permette di automatizzare l’intera procedura d’installazione di Ruby, nel caso specifico di questa trattazione รจ stata utilizzala la relase Ruby 1.9.3, cioรจ l’ultima disponibile al momento corrente anche se non ancora stabile. Una volta scaricato l’installer, questo potrร essere lanciato come un qualsiasi altro eseguibile attraverso un semplice doppio click sul file “rubyinstaller-1.9.3-p125.exe”, naturalmente, se utilizzate una versione differente del package il nome dell’applicazione potrebbe cambiare, ma il prefisso sarร sempre “rubyinstaller-” seguito dal numero di versione. La prima operazione che ci verrร richiesta in installazione sarร quella relativa all’accettazione della licenza d’utilizzo, lette le clausole potremo procedere e passare al setup vero e proprio.
In questa fase ci verrร richiesto il percorso alla cartella che conterrร tutti i file necessari per il funzionamento di Ruby, inoltre avremo la possibilitร di scegliere se:
- installare il supporto per Tcl/Tk, “Tcl” (Tool Command Language) o “tickle”, รจ un linguaggio scripting che viene comunemente utilizzato per prototipizzare applicazioni anche dotate di GUI (Graphical User Interface o Interfaccia Grafica Utente) basate su interpreti (gli engine dei linguaggi) ed effettuarne i test; “Tk” รจ invece estensione che mette a disposizione un set di tools per realizzare GUI anche in combinazione con linguaggi quali Ruby;
- aggiungere gli eseguibili Ruby alla propria PATH di sistema, in questo modo il linguaggio sfrutterร le variabili d’ambiente di Windows in modo che la sua installazione sia disponibile da qualsiasi percorso all’interno del file system; si tratta di un’opzione molto utile da punto di vista pratico, tenete conto perรฒ che se gestite altre installazioni di Ruby sullo stesso terminale queste potrebbero essere influenzate dalla selezione di tale voce.
- permettere di lanciare gli scritps Ruby con un semplice doppio click sui file “.rb” e “.rbw” o semplicemente digitandone il nome da Prompt; anche per questa associazione vale la stessa avvertenza specificata nel punto precedente.
Selezionate le voci di nostro interesse e clickato su “Install”, l’eseguibile non farร altro che portare la procedura a conclusione senza alcun intervento dell’utilizzatore; terminata l’installazione potremo clickare su “Finish” per abbandonare il Wizard di setup. Ora apriremo il Prompt di Ms Dos e procederemo con l’installazione di RoR come RubyGem; le RubyGems fanno riferimento ad un gestore di librerie pacchettizzate per Ruby che rappresentano uno standard (Gems) per la distribuzione di applicazioni scritte in Ruby. Per installare una “Gem” bisognerร lavorare su un Pc connesso ad Internet e lanciare il comando “gem install” seguito dal nome del programma che si desiderato; per cui, nel caso specifico di RoR, dovremo digitare la seguente istruzione:
gem install rails
Il gestore di packages procederร autonomamente all’installazione, la procedura prevista potrebbe perรฒ richiede un tempo piรน o meno lungo a seconda delle risorse disponibili sul sistema e, naturalmente, della larghezza della banda Internet.
Conclusa anche la fase di installazione di RoR, potremo creare il nostra primo progetto Rails in un percorso a scelta; se avete aperto il Prompt sulla directory d’installazione di Ruby, potreste per esempio creare una cartella denominata “project” all’interno della quale salvare l’applicazione generata, come nell’esempio seguente:
C:Ruby193>md project
C:Ruby193>rails new project/my_app
Il primo comando creerร la directory in cui memorizzare le cartelle di progetto, mentre l’istruzione “rail new”, seguita dal nome del progetto completo di percorso, genererร tutti i file e le cartelle per il suo funzionamento e la sua implementazione.
Installazione di RoR su Linux
Fondamentalmente, le procedure per la creazione di un ambiente di sviluppo basato su RoR in Linux variano sulla base della distribuzione utilizzata; Ubuntu รจ una delle distro piรน diffuse tra quelle basate sul Kernel del Pinguino, per cui sarร il sistema operativo di riferimento per il capitolo corrente, le procedure descritte saranno perรฒ valide anche per Debian, varianti di Debian e per tutte le distribuzioni che si basano su quest’ultima. Prima di passare alla fase vera e propria dell’installazione, sarร bene lanciare da Terminale il comando di aggiornamento dei packages disponibili sul sistema in modo da essere sicuri di lavorare su quelli piรน aggiornati, l’istruzione richiesta sarร quindi la seguente:
$ sudo apt-get update
Ci verrร richiesta la password utente e, una volta digitata quest’ultima e clickato su [Invio], la restante procedura di aggiornamento verrร eseguita automaticamente. Terminato l’update, potremo digitare, sempre da Terminale, l’istruzione per l’installazione di Ruby:
$ sudo apt-get install ruby
Il sistema si occuperร di ricercare la versione piรน recente (e stabile) del linguaggio e a rilevare le dipendenze necessarie per il buon esito dell’installazione; fatto questo, ci verrร richiesto di confermare il proseguimento della procedura. Verranno quindi scaricati dai repository tutti i package necessari e non sarร richiesto un ulteriore intervento da parte dell’utente sino alla conclusione delle fasi richieste; la presenza di una precedente installazione di Ruby non dovrebbe dare luogo ad alcun conflitto.
Se tutto dovesse andare per il meglio, si potrร procedere con la creazione dell’ambiente Rails tramite RubyGems, ma prima di fare questo sarร necessario verificare che quest’ultimo sia stato installato attraverso il seguente comando:
$ sudo apt-get remove --purge rubygems
Se RubyGems non รจ presente, il sistema risponderร con la seguente notifica:
Il pacchetto rubygems non รจ installato e quindi non รจ stato rimosso.
Si dovrร quindi procedere con l’installazione delle RubyGems digitando l’istruzione:
$ sudo apt-get install rubygems
Anche in questo caso il sistema procederร automaticamente fino al termine della procedura scaricando ed installando tutti i package necessari.
Una volta rese disponibili anche le RubyGems, si potrร passare all’installazione di RoR tramite il comando:
$ sudo gem install rails
Questa sarร con tutta probabilitร la fase che richiederร piรน tempo in assoluto per essere completata, i pacchetti da scaricare sono infatti molti e se, come capita non di rado, avete utilizzato Ubuntu per dare nuova vita ad un Pc datato o disponete di una connessione lenta, essa potrebbe richiedere qualche minuto prima della conclusione. Terminata anche questa procedura, รจ consigliabile installare un’ulteriore Gem, il Bundler, esso infatti mette a disposizione unsistema di gestione delle Gems nei progetti basati su Rails:
$ sudo gem install bundler
A questo punto, l’ambiente di sviluppo per la realizzazione applicazioni Rails sarร pronto per l’utilizzo, si potrร quindi dar vita ad un primo progetto creando una cartella nel quale salvarlo e lanciando in comando “rails new”:
$ mkdir project
$ rails new project/my_app
Fatto questo, avremo un progetto RoR pronto per la creazione della nostra applicazione.
Installazione di RoR su Mac Os X
Come sottolineato nel capitolo riguardante l’installazione sulle distribuzioni Linux, anche la procedura richiesta per creare un ambiente Rails in Mac Os X puรฒ variare a seconda della versione corrente del sistema operativo; le operazioni descritte di seguito sono state eseguite su Os X Lion ma dovrebbero essere valide anche per Snow Leopard.
La prima operazione da compiere sarร qualla di scaricare ed installare Xcode, la nota IDE (Integrated development environment, “ambiente di sviluppo integrato”) creata dai laboratori della Casa di Cupertino per lo sviluppo di applicazioni destinate a funzionare su Mac OS X e iOS. Tale componente non รจ richiesto per le features messe a disposizione, ma per le librerie in dotazione con Xcode, come per esempio il compilatore multi-target GCC (GNU Compiler Collection) necessario per Ruby. Xcode viene fornito in bundle con il sistema operativo Apple a partire dalla versione Mac OS X 10.3 (Panther), ma se non lo avete installato potrete scaricarlo gratuitamente dalla sezione dedicata ai developers del sito Internet di Cupertino. Per installarlo, una volta eseguito il download, sarร sufficiente un doppio click sull’icona del package.
Una volta installato Xcode, dovrete dotarvi di un package manager se non ne avete uno giร presente nel vostro sistema; dato che Apt-get non รจ piรน disponibile per Os X Lion, potrete ricorrere ad un’alternativa altrettanto valida denominata Homebrew, un gestore appositamente concepito per le applicazioni rilasciate sotto licenza Open Source. Per poter funzionare Homebrew richiede, oltre ad Xcode, anche il Java Developer Update; una volta configurato l’ambiente tramite i requisiti richiesti, l’installazione del manager potrร essere effettuata tramite il seguente comando:
/usr/bin/ruby -e "$(/usr/bin/curl -fksSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"
Il prossimo passaggio richiederร l’installazione di Git (se assente sul sistema), cioรจ l’ormai diffusissimo sistema distribuito per il controllo di versione dei codici sorgenti realizzato da Linus Torvalds, il papร di Linux; tale procedura prevederร la digitazione della seguente istruzione:
brew install git
Da notare che per installare una qualsiasi applicazione tramite Homebrew รจ richiesto il comando “brew install” seguito dal nome del package desiderato. Ora che anche Git รจ disponibile, per poter procedere sarร prima necessario agire sul proprio profilo bash editando il file “.bash_profile” (o creandolo se insesistente) e aggiungendo in esso la seguente stringa:
export PATH=$PATH:/usr/local/git/bin/
Quindi, una volta salvate le modifiche effettuate, bisognerร procedere con un’ulteriore installazione, quella di RVM (Ruby Version Manager o Ruby enVironment (Version) Manager), uno strumento Open Source, utilizzabile da linea di comando, che permette di semplificare le operazioni di installazione, gestione e aggiornamento di ambienti Ruby (anche multipli). Per dotare la nostra piattaforma di RVM dovremo lanciare il seguente comando:
bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
Fatto questo bisognerร poi seguire le istruzioni dettate dal sistema per il completamento dell’installazione; non rimarrร quindi che installare Ruby e RoR con un’unica sequenza di comandi:
rvm install 1.9.3
rvm --default 1.9.3
gem update
gem install rails
Da notare l’opzione “–default” che permette di impostare come predefinita una specifica installazione di Ruby nel caso essa non sia l’unica presente sul sistema. Come in Windows e in Linux, potremo ora generare un primo progetto Rails attraverso il comando “rails new” salvandolo in una cartella a nostra scelta:
mkdir project
ails new project/my_app
La procedura d’installazione di RoR su Mac Os X รจ probabilmente la piรน articolata tra quelle presentate fino ad ora, una volta terminata con successo essa permetterร perรฒ di sviluppare progetti Rails con la medesima efficacia.
Inizializzazione dell’ambiente operativo
Ora che abbiamo installato Ruby, RoR e creato il nostro primo progetto basato su Rails, potremo passare alla fase relativa all’inizializzazione del nostro ambiente di produzione; i comandi che verranno utilizzati nel corso di questa trattazione sono indipendenti dal sistema operativo adottato, per cui, anche se gli esempi proposti faranno riferimento a Windows, essi potranno essere riprodotti fedelmente sia su Linux che su Mac Os X. Prima di procedere con qualsiasi altra operazione consiglio perรฒ di effettuare un controllo di versione verificando che la release di RoR corrente sia quella piรน aggiornata, per far questo sarร sufficiente lanciare l’istruzione:
update rails
Se non dovessero essere disponibili ulteriori upgrade, il sistema risponderร inviando al Prompt la notifica:
Nothing to update
diversamente verrร segnalata la disponibilitร di una nuova versione e sarร possibile procedere con l’aggiornamento di RoR.
A questo punto si potrร lanciare il server di RoR sul progetto predecedentemente generato, per cui ci sposteremo da terminale sulla relativa cartella e poi digiteremo il comando rails server per l’inzializzazione:
C:>cd Ruby193projectmy_app
C:Ruby193projectmy_app>rails server
=> Booting WEBrick
=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-04-19 12:20:10] INFO WEBrick 1.3.1
[2012-04-19 12:20:10] INFO ruby 1.9.3 (2012-02-16) [i386-mingw32]
[2012-04-19 12:20:10] INFO WEBrick::HTTPServer#start: pid=2836 port=3000
Il sistema reagirร all’istruzione attivando innanzitutto WEBrick, che รจ in pratica la libreria di Ruby che mette a disposizione un basilare servizio HTTP Web server per le applicazioni; in secondo luogo verrร resa operativa la “porta d’ascolto” per le chiamate provenienti dal client, questa sarร di default la “3000” e funzionerร esattamente come quella utilizzata da altri Web server (si pensi per esempio ad Apache) generalmente in “attesa” delle richieste sulla porta “8080”.
Da notare che, tra le notifiche relative all’avvio del server RoR, ve n’รจ anche una che segnala il comando necessario per l’arresto (shutdown) del servizio, esso consiste nella combinazione di tasti [Ctrl]+[C]. Ho notato perรฒ che alcune versioni di Rails non producono il comportamento atteso da questa istruzione, facendo si che il server continui a rimanere attivo; fortunatamente esiste comunque una combinazione di tasti alternativa, [Ctrl]+[Pause/Break], che permetterร di arrestare il Rails server nell’eventualitร che [Ctrl]+[C] non dovesse funzionare.
Adesso che il servizio รจ attivo, sarร possibile avviare il nostro browser Internet preferito e digitare nella barra degli indirizzi la seguente URL:
http://localhost:3000
Se tutto dovesse andare per il meglio il Rail server metterร a disposizione la seguente pagina Web:
E’ utile sottolineare che il Rails server terrร traccia della chiamate da parte del client, infatti, se avete lasciato aperto il terminale, noterete la comparsa di alcuni messaggi simili ai seguente:
Started GET "/assets/rails.png" for 127.0.0.1 at 2012-04-19 12:42:45 +0200
Served asset /rails.png - 304 Not Modified (2ms)
Started GET "/assets/rails.png" for 127.0.0.1 at 2012-04-19 12:43:19 +0200
Served asset /rails.png - 200 OK (0ms)
Attraverso di essi viene in pratica notificato il caricamento del file”rails.png”, esso non รจ altro che l’immagine del logo di RoR presente nella pagina Internet precedentemente caricata. Una volta attivato l’ambiente operativo lanciando il server Rails, sarร possibile passare alla fase relativa alla creazione di un’applicazione RoR.
RoR e database: installare MySQL
Ruby On Rails รจ stato sviluppato implementando con particolare attenzione le funzionalitร destinate all’interazione del framework con le basi di dati e le informazioni in esse archiviate; tra i numerosi DBMS supportati da RoR, per citare soltanto alcuni di quelli rilsciati sotto licenza Open Source, รจ possibile fare riferimento a MySQL, SQLite e PostgreSQL. Dato che il Database Manager di riferimento per questa trattazione sarร MySQL, la prima operazione da compiere sarร quella relativa all’installazione della Gem necessaria per il dialogo con questa applicazione; una volta aperto il terminale dovremo quindi digitare la seguente istruzione che potrร essere lanciata da qualsiasi percorso:
gem install mysql
In alternativa (consigliata) รจ possibile installare la Gem “mysql2”, una libreria veloce e molto stabile per l’interazione con MySQL:
gem install mysql2
Fatto questo, dovremo recarci sulla directory d’installazione di RoR e raggiungere la cartella “project/my_app/config/” precedentemente creata tramite il comando “rails new”, in essa รจ presente il file “database.yml”; aprendolo con un editor di testo (รจ sufficiente il Blocco Note) noteremo come di default il progetto presenti una configurazione relativa al DBMS SQLite:
# SQLite version 3.x
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
adapter: sqlite3
database: db/test.sqlite3
pool: 5
timeout: 5000
production:
adapter: sqlite3
database: db/production.sqlite3
pool: 5
timeout: 5000
Quest’ultima dovrร quindi essere modificata in modo da utilizzare MySQL come DBMS predefinito, prima di fare questo sarร perรฒ necessario fare riferimento ai tre ambienti previsti da RoR per l’interazione con le basi di dati:
- “development“: รจ l’ambiente destinato allo sviluppo locale dell’applicazione prima delle fasi di test e di produzione (messa on-line);
- “test“: รจ l’ambiente utilizzabile in seguito alla fase di sviluppo per l’esecuzione dei test automatizzati sull’applicazione prima della fase di produzione;
- “production“: รจ l’ambiente a cui farร riferimento l’applicazione una volta resa pubblicamente disponibile come servizio.
Per modificare il file “database.yml” in modo che questo interagisca con MySQL, potremo quindi utilizzare delle nuove impostazioni di configurazione sul modello delle seguenti:
development:
adapter: mysql2
encoding: utf8
database: my_app_development
pool: 5
username: nome_utente
password: password_utente
host: localhost
port: 3306
socket: /tmp/mysql.sock
test:
adapter: mysql2
encoding: utf8
database: my_app_test
pool: 5
username: nome_utente
password: password_utente
host: localhost
port: 3306
socket: /tmp/mysql.sock
production:
adapter: mysql2
encoding: utf8
database: my_app_production
pool: 5
username: nome_utente
password: password_utente
host: localhost
port: 3306
socket: /tmp/mysql.sock
Per tutti e tre gli ambienti di riferimento sarร quindi necessario indicare:
- L’adapter, nel nostro caso “mysql2” che permetterร l’interazione con il DBMS;
- l’encoding (codifica di caratteri) Unicode relativo ai dati manipolati, nel nostro caso verrร utilizzato UTF-8;
- il nome del database che dovrร essere diverso per ciascun ambiente;
- il numero massimo (pool) delle connessioni indirizzabili al Database Manage per ciascun thread (processo)r;
- la username relativa all’utente attraverso il quale l’applicazione interagirร con il DBMS e la password necessaria per l’autenticazione dell’utente stesso;
- l’host di MySQL, cioรจ il nome della macchina che ospita il servizio che รจ generalmente “localhost” nelle istallazioni locali;
- la “porta d’ascolto” utilizzata dal Database Manager per attendere le richieste dai client, “3306” รจ la porta predefinita assegnata in installazione;
- il percorso al socket per la connessione con MySQL.
Una volta effettuate e salvate le modifiche richieste (ricordiamoci di modificare il parametri associati a “username” e “password” con quelli relativi alla nostra installazione di MySQL), RoR ci permetterร di creare i database di sviluppo e test precedentemente definiti da terminale. Per fare ciรฒ utilizzeremo un’istruzione basata sulla Gem “rake”, per prima cosa, quindi, dovremo installare quest’ultima da un qualsiasi percorso sul file system:
gem install rake
Rake รจ in pratica un “command runner”, cioรจ un tool che ci permetterร di accedere velocemente a comandi Rails utili per lo sviluppo della nostra applicazione; ora finalmente potremo lanciare il comando per la generazione delle basi di dati dal percorso della nostra applicazione:
C:Ruby193projectmy_app>rake db:create
Ottenuti i database desiderati (per il momento ancora vuoti), sarร possibile procedere con la creazione di una prima applicazione basata su Rails.
Creiamo la nostra prima Web Application con RoR
Per il funzionamento di una semplice applicazione basata su Ruby On Rails sono necessari almeno due elementi, cioรจ un Controller e una View; la generazione di tali componenti puรฒ essere effettuata attraverso una singola istruzione da linea di comando basata sul comando “rails generate”:
C:Ruby193projectmy_app>rails generate controller home index
la quale produrrร il seguente output:
create app/controllers/home_controller.rb
route get "home/index"
invoke erb
create app/views/home
create app/views/home/index.html.erb
invoke test_unit
create test/functional/home_controller_test.rb
invoke helper
create app/helpers/home_helper.rb
invoke test_unit
create test/unit/helpers/home_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/home.js.coffee
invoke scss
create app/assets/stylesheets/home.css.scss
L’istruzione porterร alla generazione del Controller e della Home Page relativi all’applicazione; da notare (come risulta evidente dall’output) che in questa fase verranno invocate una serie di classi destinate a strutturare l’applicazione generata:
- erb: mette a disposizione un template system il cui compito รจ nel caso specifico la generazione della home come elemento front end della view;
- test_unit: fornisce gli strumenti per la progettazione, il debug e la valutazione del codice sorgente e del suo funzonamento;
- helper: gli helpers sono sostanzialemente delle porzioni di codice, o snippets, che potranno essere richiamati per evitare ripetizioni all’interno del sorgente;
- assets: consentono di comprimere e “minificare” le componenti JavaScript e CSS perchรฉ incidano meno pesantemente sui tempi di caricamento della Web application; nello specifico vengono utilizzati il linguaggio CoffeeScript per snellire i sorgenti degli script JS e l’estensione SCSS (Sass CSS) per la semplificazione della sintassi nelle regole di stile.
A ben vedere, il risultato del comando precedentemente inviato non รจ altro che una applicazione Web completa, ha infatti una Home Page, un foglio di stile per la formattazione, un file JavaScript per le funzionalitร client side e una base per la realizzazione di un template; mancano quindi soltanto i contenuti da gestire.
Riguardo all’ultimo punto indicato, sarร possibile intervenire immediatamente editando con un qualsiasi editor testuale il file “index.html.erb” presente sul percorso “app/views/home/” della nostra applicazione, esso รจ in pratica il template che permetterร di visualizzare gli output derivanti dalle chiamate al metodo “index” nel controller “home”; al suo interno potremo inserire direttamente del markup HTML come nell’esempio seguente:
<h1>La mia prima applicazione con Rails</h1>
Fatto questo, dovremo recarci (da terminale o manulamente) sulla cartella “public” della nostra applicazione ed eliminare (o rinominare) il file “index.html” che รจ la Home Page di default della nostra installazione di RoR, quella intitolata “Welcome Aboard” per intenderci.
Ora che non sarร piรน disponibile l’index predefinito per la Web application, dovremo definirne uno noi e, per far questo, sarร necessario editare il file “routes.rb” presente nella cartella “config” della nostra applicazione; esso รจ in pratica un “routing file”, perchรฉ indica al Rails server verso quale pagina devono essere instradate le richieste dirette alla Home e ad altre pagine.
Tra le varie istruzioni presenti in “routes.rb” รจ contenuta anche la seguente stringa:
# root :to => 'welcome#index'
Essa di default indica che l’Home Page dell’applicazione dovrร esse la pagina di benvenuto prodotta da Rails nel momento in cui รจ stata generata l’applicazione; per stabilire il nuovo file su cui redirigere le richieste dovremo quindi modificare quanto scritto sostituendo “welcome” con “home” e decommentare la riga eliminando il simbolo del cancelletto (“#”) posto dinnanzi ad essa:
root :to => 'home#index'
Ora potremo aprire il nostro browser Web preferito e digitare nella barra degli indirizzi la seguente URL:
http://localhost:3000/
Se tutto dovesse andare per il meglio, al posto della “Welcome page” o della notifica di errore per la sua eliminazione dovremmo visualizzare una pagina bianca contenente la stringa “La mia prima applicazione con Rails”. La nostra Web application Rails comincia quindi a prendere forma, ma nel corso dei prossimi capitoli diventerร via via piรน aticolata.
Generare codice con lo Scaffolding
In Ruby On Rails tutto รจ stato concepito per essere piรน immediato, piรน comodo e meno macchinoso per lo sviluppatore; perchรฉ scrivere migliaia di righe di codice sorgente quando questo compito puรฒ essere svolto da delle librerie? Un’ulteriore conferma di tale caratteristica del framework รจ data dal supporto di quest’ultimo ad un meccanismo, denominato Scaffolding, per la generazione automatica del codice.
“Scaffolding” non รจ un termine facilmente traducibile con una corrispondente parola in Italiano (“impalcatura”?), questo perchรฉ esso fa riferimento a numerosi ambiti (รจ presente persino in psicologia!); per quando riguarda lo sviluppo di applicazioni per Internet, รจ possibile definire lo Scaffolding come una tecnica propria dei framework Model-View-Controller, attraverso la quale l’utilizzatore ha la possibilitร di definire delle specifiche sull’impiego di una base di dati da parte di un programma; un compilatore si occuperร poi di generare il sorgente necessario all’applicativo per l’esecuzione di operazioni CRUD (create, read, update & delete) a carico dei record manipolati.
Per proporre un esempio pratico riguardante l’utilizzo dello Scaffolding, รจ possibile procedere con la specifica di una struttura di dati che preveda di associare alla risorsa “New” alcuni fields:
- l’autore del contenuto, un dato di tipo stringa;
- il titolo del contenuto, anch’esso di tipo stringa;
- il testo, quindi il contenuto stesso, dato di tipo text.
Il comando necessario per la creazione della risorsa “New” dovrร basarsi sull’istruzione “rails generate scaffold” seguita dal nome della stessa e dai campi relativi ad essa; una volta aperto il terminale Prompt dovremo quindi digitare quanto segue:
C:Ruby193projectmy_app>rails generate scaffold New autore:string titolo:string testo:text
L’esecuzione dell’istruzione porterร alla visulizzazione del seguente output:
invoke active_record
create db/migrate/20120425095451_create_news.rb
create app/models/new.rb
invoke test_unit
createtest/unit/new_test.rb
createtest/fixtures/news.yml
route resources :news
invoke scaffold_controller
create app/controllers/news_controller.rb
invoke erb
createapp/views/news
createapp/views/news/index.html.erb
createapp/views/news/edit.html.erb
createapp/views/news/show.html.erb
createapp/views/news/new.html.erb
createapp/views/news/_form.html.erb
invoke test_unit
createtest/functional/news_controller_test.rb
invoke helper
createapp/helpers/news_helper.rb
invoketest_unit
create test/unit/helpers/news_helper_test.rb
invoke assets
invoke coffee
createapp/assets/javascripts/news.js.coffee
invoke scss
createapp/assets/stylesheets/news.css.scss
invoke scss
identical app/assets/stylesheets/scaffolds.css.scss
Sulla base di quanto proposto, si tenga presente che quella che si sta effettuando non รจ la procedura per il popolamento di un database (cosa che avverrร in seguito), anche se la natura delle operazioni svolte potrebbe farlo pensare, ma di una struttura di file.
Infatti, il comando per la generazione dello Scaffold produrrร quanto segue in esecuzione:
- “db/migrate/20120424140329_create_news.rb”: si tratta di un file denominato migration, esso verrร utilizzato per la creazione della tablella che dovrร essere inserita nel database; ogni “migration” viene marcata inserendo nel nome del file corrispondente un timestamp che la renda identificabile univocamente;
- “app/models/new.rb”: รจ il Model della risorsa “New”;
- “test/unit/new_test.rb”: รจ la routine per l’Unit Test associata al Model;
- “test/fixtures/news.yml”: associa dei dati generici, utilizzabili a scopo di test, ai campi precedentementemente definiti;
- “app/controllers/news_controller.rb”: รจ il controller della risorsa “New”;
- “app/views/news”: รจ la cartella destinata al salvataggio delle Views;
- “app/views/news/index.html.erb”: รจ una View con funzione di index per i contenuti;
- “app/views/news/edit.html.erb”: la View per l’editing dei contenuti gestiti;
- “app/views/news/show.html.erb”: la View per la visualizzazione dei singoli contenuti;
- “app/views/news/new.html.erb”: la View per la visualizzazione di un nuovo contenuto;
- “app/views/news/_form.html.erb”: รจ uno schema basilare di modulo utilizzabile come interfaccia per la gestione dei contenuti;
- “test/functional/news_controller_test.rb”: รจ una routine per l’esecuzione di test sulle funzionalitร associate al Controller;
- “app/helpers/news_helper.rb”: contiene le funzionalitร helper per le Views dei contenuti;
- “test/unit/helpers/news_helper_test.rb”: รจ il file di Unit Test per gli helper;
- “app/assets/javascripts/news.js.coffee”: il file JavaScript del Controller;
- “app/assets/stylesheets/news.css.scss”: il foglio di stile associato al Controller;
- “app/assets/stylesheets/scaffolds.css.scss”: รจ il foglio contenente il CSS associato alle Views prodotte dallo Scaffolding.
Uno Scaffold puรฒ essere cancellato del tutto attraverso una semplice istruzione basata sul comando “rail destroy scaffold” seguita dal nome della risorsa che si vuole eliminare; nel nostro caso l’istruzione richiesta sarร per esempio:
C:Ruby193projectmy_app>rails destroy scaffold New
Se invece si desidera proseguire nello sviluppo di un’applicazione Rails sulla base dello Scaffold generato, il prossimo passaggio dovrร essere quello relativo alla popolazione del database sulla base delle specifiche definite attraverso di esso.
Creare tabelle con le migration
Grazie all’utilizzo dello Scaffolding, nel capitolo precedene abbiamo generato un file denominato “20120424140329_create_news.rb”, il suo nome รจ composto da un timestamp che ne certifica il momento della generazione e da un riferimento alla risorsa Scaffold, nel caso del nostro esempio alla risorsa “New” corrisponde il riferimento “news”; aprendo “20120424140329_create_news.rb” si potrร osservare all’interno di esso una struttura come la seguente:
class Createnews < ActiveRecord::Migration
def change
create_table :news do |t|
t.string :autore
t.string :titolo
t.text :testo
t.timestamps
end
end
end
Nel contesto di un’applicazione RoR tale file costituisce una “migration”, esso contiene infatti una classe che consente di creare la tabella definita nelle specifiche dello Scaffold e i relatvi campi; ricordate il command runner “Rake”? Bene, ora lo riutilizzaremo per eseguire l’operazione necessaria alla “migrazione”, cioรจ alla trasformazione delle specifiche precedentemente definite in istruzioni per la generazione di una tabella di database:
C:Ruby193projectmy_app>rake db:migrate
== CreateNews: migrating ================================================
-- create_table(:news)
-> 0.0811s
== CreateNews: migrated (0.0820s) =======================================
Come impostazione predefinita, Rails lavora prendendo quale riferimento l’ambiente di sviluppo, per cui l’istruzione appena lanciata si occuperร di creare la tabella nel database indicato all’interno della sezione “development” definita nel file “database.yml”; opzionalmente sarร possibile decidere di generare la tabella all’interno di un altro database, il comando seguente permetterร per esempio di eseguire tale operazione a carico del database di test:
rake db:migrate RAILS_ENV=test
Tornando all’operazione di migrazione precedentemente conclusa, interrogando MySQL tramite Prompt si potrร effettuare una veloce verifica riguardante il buon esito delle istruzioni lanciate; cominciamo quindi con il visualizzare le tabelle presenti all’interno del database per lo sviluppo (“my_app_development”):
mysql> use my_app_development
Database changed
mysql> show tables;
+------------------------------+
| Tables_in_my_app_development |
+------------------------------+
| news |
| schema_migrations |
+------------------------------+
2 rows in set (0.00 sec)
La tabella “news”, relativa alla risorsa “New” specificata tramite lo Scaffolding, รจ dunque presente nell’archivio; ora effettuaremo lo stesso controllo a carico dei campi:
mysql> show columns from news;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| autore | varchar(255) | YES | | NULL | |
| titolo | varchar(255) | YES | | NULL | |
| testo | text | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)
Grazie a questa verifica รจ possibile rendersi conto della potenza di Rails nelle operazioni di interazione con le basi di dati e, nel caso specifico, con il DBMS MySQL; si puรฒ notare infatti come:
- il framework abbia generato autonomamente un campo per l’identificatore univoco (“id”), intero, chiave primaria e auto_incrementale da associare a ciascun record; ciรฒ รจ avvenuto anche se tale campo non era stato precedentemente definito nelle specifiche dello Scaffolding;
- Rails ha attribuito, sempre in modo automatico, il tipo di dato VARCHAR ai campi “autore” e “titolo” che erano stati specificati come “string” nello Scaffold;
- sono stati generati, senza la necessitร di alcun intervento da parte dello sviluppatore, i campi “crated_at” (“creato il..”) e “updated_at” (“aggiornato il..”) associati al tipo di dato “DATETIME”; grazie ad essi sarร possibile disporre di un riferimento temporale per ciascun record che verrร registrato o manipolato tramite l’applicazione.
Dalla struttura della tabella appena generata comincia ad emergere la natura CRUD del nostro applicativo che continua a prendere forma; tutte le funzionalitร per la manipolazione e la visualizzazione dei dati saranno utilizzabili via browser Web, quello che otterremo alla fine del nostro lavoro sarร un semplice esempio di News Manager basato su Rails.
Attivazione dell’applicazione e routing
Fino ad ora abbiamo configurato un ambiente integrato per lo sviluppo di applicazioni Rails, creata una prima applicazione, generati i database, realizzata la struttura dei dati e dei file con lo Scaffolding e popolate le basi di dati con tabelle e campi. Tutte queste operazioni sono state eseguite da Prompt o terminale con un unico intervento manuale a livello di codice sorgente, la digitazione di una stringa delimitata dai tags “<h1></h1>” all’interno del file “index.html.erb” situato sul percorso “app/views/home”; ora riapriremo quel file e, dopo la stringa iniziale inseriremo il codice necessario per l’inserimento di un link, concluse le modifiche il codice di pagina dovrebbe presentarsi in questo modo:
<h1>La mia prima applicazione con Rails</h1>
<%= link_to 'News manager', news_index_path %>
“link_to” รจ un metodo messo a disposizione nativamente da RoR sotto forma di helper, esso ha la funzione di generare un collegamento ipertestuale che abbia come descrizione il primo parametro passato gli come argomento (nel nostro caso “News manager”), mentre avrร come destinazione la risorsa specificata nel secondo parametro che, nell’esempio, รจ il percorso relativo all’indice delle news gestite tramite l’applicazione. Una volta salvate le modifice apportate, non sarร necessario riavviare il server Rails per confermarle, infatti in fase di sviluppo quest’ultimo sarร in grado di ricaricare le pagine Web prodotte dall’applicazione ad ogni nuova richiesta da parte del client; apriamo quindi il nostro browser e digitiamo l’indirizzo:
http://localhost:3000/
L’Home Page dell’applicazione dovrebbe essere simile a quella reppresentata nell’immagine sottostante:
Ora clickiamo sul link “News manager” prededentemente inserito, in questo caso dovrebbe aprirsi una pagina come la seguente:
In tale pagina verranno elencati, quando presenti, tutti i valori inseriti all’interno della tabella del database incolonnati sotto i relativi campi, il link inserito sulla pagina porterร invece al form per l’inserimento dei nuovi record; di sicuro la descrizione “New New” per il collegamento (che significa in pratica “Inserisci una nuova notizia”) non รจ il masssimo, ma in seguito vedremo come sia facile tradurre, formattare e adattare ogni elemento delle pagine Web con una semplice azione di editing a carico delle Views.
Avrete notato che il framework รจ in grado di generare e riconoscere automaticamente i percorsi che collegano le varie pagine; nella modifica apportata alla Home Page abbiamo dovuto inserire soltanto un link verso la risorsa che consente la visualizzazione dei contenuti, per il resto tutti gli altri collegamenti verrano messi a disposizione nativamente dall’applicazione senza un nostro intervento. Ciรฒ รจ possibile per via del fatto che le regole di routing per l’instradamento delle richieste vengono generate al momento dello Scaffolding, per avere una loro panoramica completa รจ possibile digitare da Prompt il seguente comando:
rake routes
Questo il risultato prodotto:
news_index GET /news(.:format) news#index
POST /news(.:format) news#create
new_news GET /news/new(.:format) news#new
edit_news GET /news/:id/edit(.:format) news#edit
news GET /news/:id(.:format) news#show
PUT /news/:id(.:format) news#update
DELETE /news/:id(.:format) news#destroy
home_index GET /home/index(.:format) home#index
root / home#index
Analizzando quanto stampato in output troviamo un mapping completo della struttura applicativa, per cui ad ogni percorso corrisponderร un metodo HTTP, un’azione e una determinata funzionalitร :
- metodi GET e POST per il percorso “/news” che ha come azioni “index” o “create” e come funzione quella di visualizzare l’elenco delle news o quello di crearne una nuova;
- metodo GET per il percorso “/news/new” che ha come azione “new” e il compito di generare un form HTML per l’inserimento di ulteriori news;
- metodo GET per il percorso “/news/:id/edit” che ha come azione “update” e il compito di generare un form HTML per l’aggiornamento di un record;
- metodi GET, PUT e DELETE per il percorso “/news/:id” che ha come azioni quelle di mostare, aggiornare e cancellare un determinato contenuto;
- metodo GET per il percorso “home/index” che ha il compito di indicizzare i contenuti in home;
- percorso “/”, Root del Reails server.
Durante lo Scaffolding Rails crea automaticamente degli helper in grado di restituire il percorso relativo ad una determinata risorsa, per cui, ad esempio, “news_index_path” sarร una costante che avrร come valore “/news”, mentre “new_news_path” corrisponderร a “/news/new”.
Ora che sappiamo come “muoverci” tra i percorsi della nostra applicazione, potremo passare alla parte che riguarda il suo utilizzo, cominciando con il descrivere una prima modalitร per l’inserimento dei contenuti.
Validazione dei parametri e Rails console
A questo punto abbiamo un’applicazione Rails completa che ci permetterร di visualizzare, inserire, modificare e cancellare i dati presenti nella tabella di sviluppo; essa non prevede perรฒ alcun controllo sugli input, per cui potremo colmare questa mancanza agendo sul Model. Nel caso specifico il file da modificare รจ “new.rb”, raggiungibile dal percorso “app/models/” interno alla cartella della nostra applicazione; in esso troveremo poche righe di codice:
class New < ActiveRecord::Base
attr_accessible :autore, :testo, :titolo
end
La classe contenuta non fa altro che presentare i nomi dei campi definiti nel corso dello Scaffolding, quindi, potremmo per sempio validare i parametri “autore”, “titolo” e “testo” assegnando ad ognuno di essi una lunghezza minima o massima, per far questo dovremo editare il contenuto di “new.rb” nel modo seguente:
class New < ActiveRecord::Base
attr_accessible :autore, :testo, :titolo
validates :autore, :length => { :minimum => 5 }
validates :titolo, :length => { :maximum => 10 }
validates :testo, :length => { :maximum => 500 }
end
Una volta effettuate e salvate le modifiche desiderate potremo metterle alla prova; un sistema rapido per i test di inserimento รจ rappresentato dalla “console“, una funzionalitร che permette di lanciare istruzioni da linea di comando per l’interazione con un’applicazione; avviare la console รจ semplice, basterร richiamarla da terminale:
C:Ruby193projectmy_app>rails console
Ora, proveremo ad inserire un nuovo record, limitandoci ad associare un valore al parametro “autore”; per far questo digiteremo:
irb(main):001:0> p = New.new(:autore => "Ruby")
Dando un [Invio] il sistema risponderร completando la nostra istruzione in questo modo:
=> #<New id: nil, autore: "Ruby", titolo: nil, testo: nil, created_at: nil,
updated_at: nil>
Ora cercheremo di memorizzare in tabella il nuovo record e, a questo scopo, digiteremo il nome dell’oggetto (“p”) creato dalla precedente istanza associandolo al metodo “save”:
irb(main):013:0> p.save
Questa volta il sistema risponderร come segue:
โ[1mโ[35m (0.0ms)โ[0m BEGIN
โ[1mโ[36m (0.0ms)โ[0m โ[1mROLLBACKโ[0m
=> false
La notifica “false” indica in pratica che non รจ stato possibile eseguire l’istruzione per il verificarsi di un errore; per conoscere la natura del malfunzionamento potremo quindi utilizzare la clausola “errors.full_messages” concatenandola in istruzione al nome dell’oggetto:
irb(main):014:0> p.errors.full_messages
=> ["Autore is too short (minimum is 5 characters)"]
La risposta del sistema appare abbastanza chiara: il termine “Ruby” รจ composto da sole quattro lettere, ma non in “new.rb” abbiamo definito un controllo che associa a questo parametro una lunghezza non inferiore alle 5 lettere, per cui l’istruzione non potrร essere eseguita. A questo punto sarร quindi possibile formulare una secondo istruzione rispettando i vincoli di validazione per gli input, come nell’esempio seguente:
irb(main):018:0> p = New.new(:autore => "Rails", :titolo => "Test RoR", :testo=> "Prova di contenuto")
=> #<New id: nil, autore: "Rails", titolo: "Test RorR", testo: "Prova di contenuto",
created_at: nil, updated_at: nil>
irb(main):019:0> p.save
โ[1mโ[35m (0.0ms)โ[0m BEGIN
โ[1mโ[36mSQL (0.0ms)โ[0m โ[1m
INSERT INTO `news` (`autore`, `created_at`, `testo`,
`titolo`, `updated_at`) VALUES ('Rails', '2012-04-28 07:40:48',
'Prova di contenuto', 'Test RorR', '2012-04-28 07:40:48')โ[0m
โ[1mโ[35m (31.2ms)โ[0m COMMIT
=> true
L’istruzione non farร altro che convertire il nostro comando Rails in un query verso il database, “true” indica che l’esecuzione รจ andata a buon fine, quindi, potremo accedere alla tabella di sviluppo per verificare l’inserimento dei dati:
mysql> select * from news;
+----+--------+-----------+--------------------+---------------------+---------------------+
| id | autore | titolo | testo | created_at | updated_at |
+----+--------+-----------+--------------------+---------------------+---------------------+
| 7 | Rails | Test RoR | Prova di contenuto | 2012-04-28 07:40:48 | 2012-04-28 07:40:48 |
+----+--------+-----------+--------------------+---------------------+---------------------+
1 row in set (0.00 sec)
E’ da segnalare il fatto che la Rails console puรฒ essere utilizzata in tutte le sue funzionalitร anche senza che vengano apportate effettivamente delle modifiche a carico dei dati in tabella, per questo scopo รจ infatti disponibile un meccanismo di sandbox grazie al quale simulare l’invio e il funzionamento dei comandi evitando che questi abbiano effetto sui record; la sandbox potrร essere attivata attraverso l’opzione “–sandbox” o l’alias “-s”:
C:Ruby193projectmy_app>rails console --sandbox
Loading development environment in sandbox (Rails 3.2.3)
Any modifications you make will be rolled back on exit
irb(main):001:0>
Per uscire dalla console basterร digitare il comando “exit” o, in alternativa, utilizzare la combinazione [Ctrl]+[d], ricordiamoci perรฒ sempre che, a differenza del Rails server, la console non opera un refresh delle pagine quando queste subiscono delle modifiche; quindi, ogni volta che si edita il contenuto di un Model sarร necessario lanciare il comando “reload!” perchรฉ il framework agisca sulla base delle nuove impostazioni.
irb(main):001:0> reload!
Reloading...
=> true
Nel corso dei prossimi capitoli continueremo naturalmente a parlare della parte funzionale (CRUD) della nostra applicazione, prima perรฒ ci occuperemo di un altro aspetto importante, quello relativo alla presentazione dei dati.
Views e personalizzazione del layout
Ora che abbiamo inserito un primo record nella nostra tabella, potremo utilizzare il nostro browser Web per ritornare sull’applicazione creata e visualizzare tale contenuto nell’elenco delle news:
Come รจ possibile notare, il framework ha generato automaticamente il link necessari alla visualizzazione (“Show”), alla modifica (“Edit”) e alla cancellazione (“Destroy”) del record, ogni record successivamente inserito sarร associato alle medesime funzionalitร per la manipolazione dei dati. Come anticipato, la struttura delle pagine di funzione รจ data dalle Views che presiedono alla loro presentazione; nel caso della nostra applicazione, sul percorso “app/views/news/” saranno presenti cinque file che corrispondono ad altrettante Views:
- “index.html.erb”: rappresenta la View relativa alla visualizzazione di tutti i record;
- “new.html.erb”: presenta il form per l’inserimento di un nuovo record;
- “show.html.erb”: mostra un singolo record e fornisce i collegamenti per la sua manipolazione;
- “_form.html.erb”: contiene il form che verrร utilizzato per le operazioni di editing;
- “edit.html.erb”: mette a disposizione il form per la modifica di un singolo record.
Per descrivere quale sia la procedura necessaria permodificare una View, รจ possibile aprire uno qualsiasi di questi file e visualizzarne il contenuto; il codice seguente sarร per esempio disponibile aprendo il file “index.html.erb” della nostra applicazione:
<h1>Listing news</h1>
<table>
<tr>
<th>Autore</th>
<th>Titolo</th>
<th>Testo</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @news.each do |news| %>
<tr>
<td><%= news.autore %></td>
<td><%= news.titolo %></td>
<td><%= news.testo %></td>
<td><%= link_to 'Show', news %></td>
<td><%= link_to 'Edit', edit_news_path(news) %></td>
<td><%= link_to 'Destroy', news, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'News New', new_news_path %>
Immaginiamo ora di voler apportare una semplice modifica al contenuto della View di Home Page, essa consisterร nella traduzione in Italiano delle voci attualmente in lingua inglese; attraverso il nostro editor di testo potremmo per esempio alterare la View in questo modo:
<h1>Visualizza tutte le news</h1>
<table>
<tr>
<th>Autore</th>
<th>Titolo</th>
<th>Testo</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @news.each do |news| %>
<tr>
<td><%= news.autore %></td>
<td><%= news.titolo %></td>
<td><%= news.testo %></td>
<td><%= link_to 'Visualizza', news %></td>
<td><%= link_to 'Modifica', edit_news_path(news) %></td>
<td><%= link_to 'Cancella', news, confirm: 'Confermi la cancellazione?', method: :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'Inserisci un nuovo record', new_news_path %>
Una volta salvate le modifiche effettuate, potremo riaprira la pagina che elenca le news e visualizzare il risultato del nostro lavoro:
Il funzionamento di questa pagina dipende da un apposito Controller contenuto nella pagina “news_controller.rb” presente sul percorso “app/controllers/” dell’applicazion, esso รจ molto ricco di configurazioni, ma a noi in questo momento interessa la parte relativa ad un’azione specifica, l’index:
def index
@news = New.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @news }
end
end
In pratica l’elemento New.all restituisce tutti i record presenti nella tabella del database al momento corrente, per far questo viene generato un array che viene memorizzato in una specifica varibile che nel nostro caso รจ chiamata @news, tale array verrร ciclato per consentire la visualizzazione dei record; i formati supportati per i dati messi a disposizione in modo predefinito sono HTML, come appena visto a proposito delle Views e JSON per l’interscambio.
Le Views generate in seguito allo Scaffolding assolvono perรฒ soltanto parzialmente i compiti relativi alla presentazione del dato e alla generazione del markup di pagina; a tale meccanismo presiedono infatti anche altre componenti dell’applicazione, per questo motivo nel prossimo capitolo continueremo a parlare di layout.
Il layout specifico per l’applicazione
Otre alle Views, per quanto riguarda l’aspetto presentazionale di un’applicazione Rails, RoR supporta una struttura basata sulla nozione di layouts; questi ultimi sono stati concepiti come una sorta di contenitori per le Views; in pratica, quando il framework restituisce tramite il browser l’output relativo ad una View, esso da vita ad un meccanismo in grado di integrare il markup della stessa all’interno dell’HTML relativo ad un layout specifico per l’applicazione corrente. Tale layout รจ valido per l’intero contesto dell’applicazione e quindi per tutti i Controllers che fanno riferimento a quest’ultima, esso viene definito all’interno del file “application.html.erb” presente sul percorso “app/views/layouts/” della cartella di progetto; aprendo questo file dovremmo visualizzare un listato simile al seguente:
<!DOCTYPE html>
<html>
<head>
<title>MyApp</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
Ora, proveremo ad applicare alcune regole di stile utilizzando CSS, per esempio potremmo cominciare con il modificare il colore di sfondo delle pagine:
<!DOCTYPE html>
<html>
<head>
<title>MyApp</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
<style type="text/css">
body
{
background-color:#b0c4de;
}
</style>
</head>
<body>
<%= yield %>
</body>
</html>
Ora, potremo visualizzare da browser l’Home Page della nostra applicazione e valutare le modifiche effettuate:
Il colore di sfondo della pagina รจ cambiato, lo stesso effetto sarร visibile su tutte le altre pagine che compongono l’applicazione; un’ulteriore modifica potrebbe essere per esempio quella di ridurre le dimensioni e il colore dei testi delimitati dai tag “<h1></h1>”:
h1
{
color:yellow;
font-size:16px;
}
Anche in questo caso si potrร visualizzare attraverso il browser Web l’esito della regola di stile appena definita.
Infine, potremmo effettuare anche delle modifiche a carico della formattazione delle tabelle:
table, th, td
{
border: 1px solid black;
}
ottenendo un risultato simile al seguente nella pagina contenente l’elenco dei record:
Proseguendo, si potrebbero associare ulteriori regole di stile a molti altri elementi della nostra applicazione, come per esempio ai link (e ai loro diversi stati), ai campi del form, ai pulsati di input o ai testi; l’unico limite sarร la nostra fantasia; l’importante รจ tenere sempre conto della regola di base che prevede di applicare modifiche alle singole Views quando si desidera agire su pagine specifiche e al file “application.html.erb” quando l’intenzione รจ quella di apportare combiamenti all’intero layout dell’applicazione.
Come avrete potuto notare, Rails offre numerose possibilitร di intervenire sul rendering delle pagine Web e degli elementi che le compongono; a breve vedremo come il framework sia in grado di organizzare la struttura di un’applicazione riutilizzando le medesime porzioni di codice per il completamento di funzionalitร differenti.
Riutilizzare codice con i partials
A questo punto abbiamo acquisito le conoscienze necessarie per la creazione di una prima, seppur semplice, applicazione Rails completa e per la modifica dei layouts ad essa associati, vale perรฒ la pena proseguire nell’analisi della struttura di tale applicazione anche per un semplice motivo pratico, infatti, a differenza degli utenti alle prime armi, gli sviluppatori piรน esperti non utilizzano sempre lo Scaffolding per la generazione dei loro progetti, in particolare quando necessitano una maggiore flessibilitร delle varie componenti funzionali e presentazionali. Per questo motivo, maggiore sarร la conoscenza delle dinamiche create dal framework, maggiori saranno le possibilitร di personalizzazione.
Un aspetto importante nell’economia della nostra applicazione รจ quella relativo all’interazione con il database per l’inserimento dei contenuti; come abbiamo visto in precedenza, esso coinvolge due azioni: “new” e “create”; nel caso specifico del nostro esempio, la prima ha il compito di effettuare l’istanza di un oggetto “New” vuoto, la seconda invece istanzia un oggetto “New” popolato tramite il form per l’inserimento di nuovi record. Per chiarire meglio il concetto esposto, รจ possibile aprire il file View “new.html.erb” contenuto sul percorso “/app/views/news/” della nostra cartella progetto; esso presenta un codice sul modello del seguente:
<h1>New news</h1>
<%= render 'form' %>
<%= link_to 'Back', news_path %>
Dal listato emerge un importante elemento funzionale, cioรจ il riferimento “<%= render ‘form’ %>”; esso presenta un esempio di partial, cioรจ una porzione di codice che puรฒ essere composta sia da markup HTML che da snippets Ruby e che potrร essere utilizzata piรน volte nel contesto di una medesima applicazione.
All’interno di una struttura CRUD abbiamo la necessitร di utilizzare due form: uno per l’inserimento dei dati e uno per il loro aggiornamento, a questo scopo Rails permette di utilizzare uno stesso partial per generare i moduli necessari in entrambi i casi, evitando in questo modo inutili ripetizioni. A conferma di ciรฒ รจ possibile aprire il file “edit.html.erb” contenuto sullo stesso percorso di “new.html.erb”:
<h1>Editing news</h1>
<%= render 'form' %>
<%= link_to 'Show', @news %> |
<%= link_to 'Back', news_path %>
Come รจ possibile notare, anche all’interno di questa View รจ presente il riferimento al partial “<%= render ‘form’ %>” e, come nel caso della Vista per l’inserimento di un nuovo record, tale elemento determina l’inclusione di un’altra View contenuta nel file denominato “_form.html.erb” che presenta una struttura come la seguente:
<%= form_for(@news) do |f| %>
<% if @news.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@news.errors.count, "error") %> prohibited this news from being saved:</h2>
<ul>
<% @news.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :autore %><br />
<%= f.text_field :autore %>
</div>
<div class="field">
<%= f.label :titolo %><br />
<%= f.text_field :titolo %>
</div>
<div class="field">
<%= f.label :testo %><br />
<%= f.text_area :testo %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Analizzando il codice visualizzato, si noterร come tutto sia organizzato per effettuare le operazioni previste con meno codice possibile ed eliminando la necessitร di ripetizioni; per fare un esempio, si noti come la prima parte del listato sia dedicata al controllo degli eventuali errori, in essa รจ contenuto un metodo, “pluralize“, che permetterร di proporre la parola “error” al singolare o al plurale a seconda del numero di errori generati. Tale metodo risulta particolarmente comodo anche per restituire al plurale parole scritte in Italiano, a questo scopo sarร possibile aprire il file “environment.rb” contenuto nella cartella “/config” della nostra applicazione e inserire delle regole (inflectors) per la pluralizzazione dei termini, ad esempio:
inflect.irregular 'errore', 'errori'
Inoltre, sarร possibile utilizzare anche le espressioni regolari, come per la regola seguente che mostra un esempio di trasformazione da singoli a plurali (e viceversa) di parole che finiscono con la desinenza “ente”:
inflect.plural /([w]*)nte$/i, '1nti'
inflect.singular /([w]*)nti$/i, '1nte'
In linea generale รจ possibile affermare che il blocco “form_for” permette di accedere ai metodi necessari per la generazione di controlli a carico dei moduli; “f.text_area :testo” impone per esempio al framework di realizzare un campo di input sotto forma di textarea e associa ad esso il nome del parametro che dovrร essere passato all’applicazione per l’inseriemnto in tabella. E’ importante precisare che sarร possibile utilizzare i metodi esclusivamente con gli attributi relativi al Model su cui รจ basato il form corrente, nel nostro esempio gli attributi consentiti saranno per esempio “autore”, “titolo” e “testo”.
Ma quali funzionalitร entrano in gioco nella gestione dei singoli record in un’applicazione basata su Rails? Affronteremo questo argomento nel prossimo capitolo.
Visualizzazione, aggiornamento e cancellazione dei record
Per proseguire, lanceremo una query utilizzando il nostro terminale allo scopo di visualizzare il contenuto del database di sviluppo e controlleremo i record presenti nella tabella della news:
mysql> select * from news;
Nella tabella creata per l’applicazione relativa a questa trattazione, รจ presente un solo record ed รจ associato ad esso l’id “7”, utilizzeremo quindi quest’ultimo per il nostro esempio, il lettore invece potrร scegliere uno qualsaisi degli id archiviati nella propria tabella; ora, se il nostro Rails server non รจ stato ancora attivato, lo lanceremo e subito dopo apriremo il nostro browser per digitare nella barra degli indirizzi un’URL simile alla seguente:
http://localhost:3000/news/7
Dovremmo visualizzare una pagina contenente dei dati simili a quelli presenti nell’immagine successiva:
La generazione di questa pagina dipende dal fatto che il framework interpreta l’URL digitata come una chiamata all’azione “show” per il contenuto relativo all’identificatore specificato come parametro, tale “id” diventa quindi un argomento (“:id”) che viene utilizzato dal metodo “New.find” per effettuare una ricerca tra i record disponibili; una volta terminata la scansione dei dati, questi vengono mostrati attraverso la View contenuta nel file “show.html.erb” presente sul percorso “/app/views/news” della nostra applicazione. Aprendo tale View sarร possibile visualizzare il codice seguente:
<p id="notice"><%= notice %></p>
<p>
<b>Autore:</b>
<%= @news.autore %>
</p>
<p>
<b>Titolo:</b>
<%= @news.titolo %>
</p>
<p>
<b>Testo:</b>
<%= @news.testo %>
</p>
<%= link_to 'Edit', edit_news_path(@news) %> |
<%= link_to 'Back', news_path %>
Come รจ possibile notare, alla fine del codice della View sono presenti due link, in questo momento a noi interessa il primo, dato che il secondo si limita a riportare l’utente alla pagina precedente rispetto a quella corrente; il collegamento ipertestuale che ha come descrizione “Edit” conduce alla pagina contenente il form per effettuare le modifiche sui singoli record. Abbiamo giร visualizzato nel capitolo precedente il codice relativo alla View per la presentazione del modulo di aggiornamento delle news, รจ quindi venuto il momento di proporre il form cosรฌ come viene generato da Rails con in piรน le modifiche da noi apportate al layout:
Il processo per l’aggiornamento di un record funziona in modo molto simile a quello necessario per la sua creazione; in questo caso il primo passaggio sarร quello relativo all’invio di una richiesta effettuata tramite il costrutto “edit_news_path(@new)” che, in pratica, passa al percorso verso il file per l’editing (“edit_news_path”) una variabile (“@new”) contenente l’informazione relativa all’identificatore del record da manipolare. L’azione “edit” viene messa a disposizione da un Controller strutturato nel modo seguente:
def edit
@new = New.find(params[:id])
end
La chiamata all’azione determina la presentazione della risorsa richiesta attraverso la View contenuta nel file “edit.html.erb” che fornisce il form completo di campi giร popolati con i dati da modificare. Anche in questo caso verra utilizzato il partial “<%= render ‘form’ %>” per l’inclusione del modulo, perรฒ, a differenza di quanto accade con la View per l’inserimento dei record, il form farร riferimento al controller NewController tramite metodo PUT e il pulsante per l’invio dei dati presenterร una descrizione differente: “Update New”.
La modifica dei dati in tabella, effettuata utilzzando in parametri inviati tramite form, sarร possibile grazie all’azione “update”; RoR utilizzerร inizialmente il parametro “:id” per rilevare l’esatto record da modificare, quindi, applicherร le modifiche e, se l’operazione di aggiornamento dovesse concludersi con esito positivo, verrร invocata l’azione “show” per visualizzare nuovamente il contenuto a conferma dell’avvenuto aggiornamento; diversamente, in presenza di qualche impedimento (ad esempio un formato non valido associato ad un paramentro), verrร effettuto un redirect alla stessa pagina del form per l’editing in modo da permettere la ricompilazione del modulo.
L’ultima funzionalitร che non puรฒ mancare in un’applicazione ispirata al modello CRUD รจ quella relativa alla cancellazione dei record, a questo scopo Rails introduce un’apposita azione, denominata “destroy”, che fa riferimento ad uno specifico controller:
def destroy
@new = New.find(params[:id])
@new.destroy
respond_to do |format|
format.html { redirect_to news_url }
format.json { head :no_content }
end
end
Dato un determinato id, “destroy” lo utilizza per rilevare il record corrispondente attraverso una ricerca in tabella e quindi concellarlo; fatto questo, il framework redireziona la navigazione tramite verso l’azione “index” del Controller.
Ora che abbiamo analizzato tutti gli aspetti funzionali della nostra prima applicazione RoR (per ora estremamente basilare), non ci resta che sfruttare le potenzialitร del framework per l’integrazione di nuove features che la rendano piรน completa.
Introdurre un Model addizionale
A questo punto del nostro approfondimento riguardante la realizzazione di un’applicazione basata sul RoR, potremo passare ad una fase piรน avanzata, cioรจ รฌquella relativa all’inclusione di funzionalitร aggiuntive; come vedremo a breve, i passaggi richiesti non differiscono di molto da quelli descritti per la creazione delle features di base del nostro progetto, in questo caso perรฒ partiremo dalla generazione del Model; quest’ultimo verrร ottenuto grazie all’apposito comando “rails generete model” che dovrร essere lanciato dal percorso della cartella della nostra applicazione:
C:Ruby193projectmy_app>rails generate model Commenti utente:string
messaggio:text new:references
invoke active_record
create db/migrate/20120504102314_create_commentis.rb
create app/models/commenti.rb
invoke test_unit
create test/unit/commenti_test.rb
create test/fixtures/commentis.yml
Nel caso specifico, creeremo un sistema di commenti che gli utenti potranno postare a corredo degli articoli; nell’esempio proposto, tale funzionalitร permetterร di manipolare tre soli campi (“utente”, il nickname del commentatore, “messaggio”, il commento vero e proprio e”new”, la chiave esterna che consentirร di mettere in relazione news e commenti), ma il lettore se lo desidera potrร rendere la struttura di questa “estensione” ancora piรน articolata. Con l’esecuzione del comando per la generazione del nuovo Model, verranno quindi creati i file indicati di seguito con tanto di percorso all’interno della directory progetto:
- “db/migrate/20100207235629_create_commentis.rb”: รจ la migration con la quale generare la tabella dei commenti e i relativi campi, il nome del file riporta un timestamp che permetterร di identificare univocamente la migration;
- “app/models/commenti.rb”: il Model associato alla funzionalitร per i commenti;
- “test/unit/commenti_test.rb”: รจ il file di Unit testing del Model per i commenti;
- “test/fixtures/commentis.yml”: una risorsa generata automaticamente al momento della creazione del Model per l’esecuzione di test;
Il file “commenti.rb” presente sul percorso “/app/models/” della nostra applicazione presenterร al suo interno una classe strutturata nel modo seguente:
class Commenti < ActiveRecord::Base
belongs_to :new
attr_accessible :messaggio, :utente
end
La parte piรน interessante del codice appena proposto riguarda sicuramente la riga:
belongs_to :new
Infatti, come potrete notare, Rails รจ in grado di capire sulla base di un dato di relazione (nel nostro caso la key “new”) e dal contesto applicativo che sussiste una rapporto tra la nuova tabella e quella giร prevista per l’applicazione di base, in pratica il framework riesce a strutturare le sorgenti di dati sulla base di indicazioni minime fornite dallo sviluppatore.
Ora si potrร passare alla fase in cui la migration, contenuta sul percorso “/db/migrate/” della cartella progetto, ci permetterร di creare un’ulteriore tabella, tale file dovrebbe presentare giร tutte le indicazioni riguardanti i campi da generare:
class CreateCommentis < ActiveRecord::Migration
def change
create_table :commentis do |t|
t.string :utente
t.text :messaggio
t.references :new
t.timestamps
end
add_index :commentis, :new_id
end
end
La creazione della tabella per i commenti all’interno del database sarร possibile grazie ad un comando a noi giร noto:
C:Ruby193projectmy_app>rake db:migrate
== CreateCommentis: migrating ================================================
-- create_table(:commentis)
-> 0.2344s
-- add_index(:commentis, :new_id)
-> 0.2705s
== CreateCommentis: migrated (0.5049s) =======================================
Al termine dell’esecuzione potremo verificare l’esito della nostra ultima migrazione:
mysql> show columns from commentis;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| utente | varchar(255) | YES | | NULL | |
| messaggio | text | YES | | NULL | |
| new_id | int(11) | YES | MUL | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.06 sec)
Ricordate il file”new.rb” contenuto nel percorso “/app/models/” della nostra applicazione? Ora lo dovremo aprire nuovamente allo scopo di effettuare una semplice modifica che consiste nell’aggiunta dell’espressione “has_many :commentis” prima dell'”end” che delimita il blocco di codice in chiusura:
class New < ActiveRecord::Base
attr_accessible :autore, :testo, :titolo
validates :autore, :length => { :minimum => 5 }
validates :titolo, :length => { :maximum => 10 }
validates :testo, :length => { :maximum => 500 }
has_many :comments
end
In questo modo concluderemo le operazioni necessarie per associare i due Models disponibili, cioรจ quello del New Manager a quello dei commenti, ad ogni “new” potranno essere associati piรน commenti.
Il nostro lavoro per l’integrazione della nuova funzionalitร non รจ perรฒ ancora conlcuso, infatti, adesso dovremo occuparci della sua parte funzionale (il Controller) e di quella presentazionale (la View).
Routing, Controller e View del model addizionale
Ora che sono state completate le operazioni necessarie per il completamento del Model, come รจ giร accaduto per il News Manager, anche per quanto riguarda i commenti sarร necessario impostare delle regole di routing attraverso le quali Rails sia in grado di instradare correttamente le diverse componenti applicative; quindi, quello che dovremo fare ora sarร editare il file “routes.rb” presente nella cartella “config/” della nostra directory progetto e aggiungere una nuova regola, essa dovrร essere posizionata dopo “resources :news” in modo che le prime quattro righe risultino scritte nel modo seguente:
MyApp::Application.routes.draw do
resources :news do
resources :commentis
end
Completato in nostro blocco per il routing salveremo il file editato e sarร possibile generare il Controller associato al Model dei commenti; a questo scopo รจ disponibile l’apposito comando denominato “rails generate controller” seguito dal nome del Controller desiderato che dovrร essere omonimo rispetto alla tabella creata tramite migration:
C:Ruby193projectmy_app>rails generate controller Commentis
create app/controllers/commentis_controller.rb
invoke erb
create app/views/commentis
invoke test_unit
create test/functional/commentis_controller_test.rb
invoke helper
create app/helpers/commentis_helper.rb
invoke test_unit
create test/unit/helpers/commentis_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/commentis.js.coffee
invoke scss
create app/assets/stylesheets/commentis.css.scss
Alcuni dei file creati svolgono una funzione molto simile a quelli giร visti in occasione dello Scaffolding utilizzato per il News manager, descriviamoli nel dettaglio:
- “app/controllers/commentis_controller.rb”: รจ il Controller della nostra nuova funzionalitร ;
- “app/views/commentis”: la cartella destinata a contenere tutte le View associate al Controller generato;
- “test/functional/commentis_controller_test.rb”: contiene i riferimenti per i test funzionali a carico del Controller;
- “app/helpers/commentis_helper.rb”: รจ l’helper file delle View per il codice riutilizzabile;
- “test/unit/helpers/commentis_helper_test.rb”: il file helper per i test unitari sulle funzioni;
- “app/assets/javascripts/commentis.js.coffee”: contine il JavaScript associato alla nuova feature;
- “app/assets/stylesheets/commentis.css.scss”: rappresenta il foglio di stile esterno contenente le regole CSS da associare ai commenti;
Il prossimo passaggio consisterร in un’ulteriore azione di editing, dovremo infatti mettere mano ad una nostra vecchia conoscenza, cioรจ il file di View “show.html.erb” contenuto sul percorso “/app/views/news/” della nostra applicazione; all’interno di esso dovremo infatti inserire il codice necessario per la visualizzazione dei commenti (quando presenti), quindi, prima del link per la modifica delle news potremo inserire delle istruzioni come le seguenti:
<h2>Visualizza i commenti</h2>
<% @new.commentis.each do |commenti| %>
<p>
<b>Utente:</b>
<%= commenti.utente %>
</p>
<p>
<b>Messaggio:</b>
<%= commenti.messaggio %>
</p>
<% end %>
Ma perchรฉ i commenti siano visualizzabili, prima sarร naturalmente necessario che questi possano essere inseriti, motivo per il quale potremo aggiungere subito dopo il blocco dei commenti un form per la loro digitazione
<h2>Inserisci un tuo commento:</h2>
<%= form_for([@new, @new.commentis.build]) do |f| %>
<div class="field">
<%= f.label :utente %>
<br />
<%= f.text_field :utente %>
</div>
<div class="field">
<%= f.label :messaggio %>
<br />
<%= f.text_area :messaggio %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Ora che abbiamo implementato le parti funzionali e prensentazionali dell’estensione per i commenti, dovremo permettere alle varie componenti di lavorare insieme; avrete infatto notato che la cartella destinata a contenere le Views per la nostra funzionalitร addizionale รจ ancora vuota; nel prossimo capitolo descriveremo quindi le procedure necessarie per il suo popolamento.
Generazione manuale delle Views
Se avete provato a testare la funzionalitร aggiuntiva per l’inclusione dei commenti e questa ancora non dovesse funzionare, non vi preoccupate! Il motivo di questo risultato รจ infatti semplice, tale estensione dell’applicazione non รจ al momento associata ad alcuna View, quindi il malfunzionamento รจ pienamente giustificato. Per rimediare a tale mancanza, dovremo recarci sulla cartella denominata “commentis” (come abbiamo visto Rails aggiunge autonomamente una “s” finale al nome del Controller per questioni legate alla pluralizzazione in lingua Inglese) che si trova all’interno del percorso “/app/views/” della directory di progetto; essa รจ vuota di default, quindi procederemo con il riempirla creando innanzitutto all’interno di essa un file denominato “_commenti.html.erb” che apriremo ed editeremo digitando il seguente codice:
<p>
<b>Utente:</b>
<%= commenti.utente %>
</p>
<p>
<b>Messaggio:</b>
<%= commenti.messaggio %>
</p>
Una volta salvato il nostro lavoro, avremo generato una prima View, quella destinata alla visualizzazione dei commenti per le singole news; ora passeremo alla creazione di una seconda View, quella relativa al form per l’inserimento dei commenti che potrร contenere un listato come quello mostrato di seguito:
<%= form_for([@new, @new.commentis.build]) do |f| %>
<div class="field">
<%= f.label :utente %><br />
<%= f.text_field :utente %>
</div>
<div class="field">
<%= f.label :messaggio %><br />
<%= f.text_area :messaggio %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Salviamo quanto digitato sempre sullo stesso percorso della View precedente e in un file denominato “_form.html.erb”; ora i piรน attenti si chiederanno il perchรฉ del fatto che proprio RoR, concepito per evitare quanto piรน possibile la presenza di ripetizioni, consenta la creazione di un’altra View per il form nel contesto di un’applicazione che ne contiene giร una; la risposta รจ immediata anche in questo caso: una nuova View ci permetterร infatti di risparmiare un buon numero di righe di codice. Vediamo come.
Aprimo il file “show.html.erb” contenuto sul percorso “/app/views/news/” e modifichiamo il codice contenuto nel modo seguente:
<p id="notice"><%= notice %></p>
<p>
<b>Autore:</b>
<%= @news.autore %>
</p>
<p>
<b>Titolo:</b>
<%= @news.titolo %>
</p>
<p>
<b>Testo:</b>
<%= @news.testo %>
</p>
<h2>Visualizza i commenti</h2>
<%= render @new.commentis %>
<h2>Inserisci un tuo commento:</h2>
<%= render "commentis/form" %>
<%= link_to 'Edit', edit_news_path(@news) %> |
<%= link_to 'Back', news_path %>
Come รจ semplice notare, ora, invece di specificare direttamente il codice necessario per la visualizzazione dei commenti e per l’integrazione del form d’inserimento degli stessi, รจ stato sufficiente ricorrere a due partials che eseguiranno lo stesso compito: “<%= render @new.commentis %>” e “<%= render “commentis/form” %>”.
Adesso che abbiamo la possibilitร di inserire i commenti e di renderli disponbili sulla pagina, non resta che introdurre la funzionalitร necessaria per la loro cancellazione; riapriamo quindi il file “_commenti.html.erb” e modifichiamo il codice presente nel modo seguente:
<p>
<b>Utente:</b>
<%= commenti.utente %>
</p>
<p>
<b>Messaggio:</b>
<%= commenti.messaggio %>
</p>
<p>
<%= link_to 'Elimina commenti', [commenti.new, commenti],
:confirm => 'Vuoi eliminare il commento?',
:method => :delete %>
</p>
La modifica effettuata permetterร di utilizzare il collegamento “Elimina commenti” per richiamare il metodo “delete” dal Controller dei commenti, quest’ultimo effettuerร una ricerca in tabella sulla base dell’identificatore selezionato che, se rilevato, permetterร la cancellazione del record. A questo scopo, bisognerร aggiungere un nuovo blocco di istruzioni alla classe “CommentsController” dell'”ApplicationController”:
def destroy
@new = New.find(params[:new_id])
@commenti = @new.commentis.find(params[:id])
@commenti.destroy
redirect_to new_path(@new)
end
In pratica, l’azione “destroy” si occuperร di scovare la “new” desiderata e di identificare il relativo commento all’interno del set “@post.commentis”; una volta cancellato il commento verrร effettuato un redirect alla pagina della “new”.
Ora che abbiamo creato una applicazione CRUD completa, questa ci consentirร di manipolare tutti i dati presenti nel nostro database, ma se desiderassimo utilizzarla in Rete non potremmo di certo renderla accessibile a chiunque, dovremo quindi proteggerla con un sistema per l’autenticazione.
Autenticazione in Rails
Il framework Ruby On Rails mette a disposizione alcune modalitร per mettere in sicurezza le applicazioni CRUD, queste ultime sono infatti generalmente destinate a fornire funzionalitร di back-end che non dovrebbero essere accessibili pubblicamente. Nel nostro caso faremo ricorso alla soluzione piรน semplice, cioรจ alla creazione di un sistema di autenticazione basato su HTTP che viene supportato nativamente da Rails attraverso un metodo appositamente dedicato denominato “http_basic_authenticate_with”. Una configurazione ideale potrebbe essere quella che prevede la possibilitร di visualizzare i contenuti senza la necessitร di alcuna procedura di login, quest’ultima dovrebbe essere invece richiesta per effettuare operazioni di inserimento, modifica e cancellazione; a questo scopo potremo agire sul file “news_controller.rb”, contenuto sul percorso “/app/controllers/” della nostra applicazione, ed editarlo aggiungendo una semplice riga di istruzioni da digitare subito dopo la dichiarazione del NewsController:
class NewsController < ApplicationController
http_basic_authenticate_with :name => "user", :password => "pass", :except => [:index, :show]
Lo schema dell’istruzione รจ abbastanza lineare:
- viene effettuata la chiamata al metodo;
- si definiscono la username e la password necessarie per l’autenticazione;
- si stabiliscono delle eccezioni introdotte dalla clausola “except” che accetta come argomenti le actions che non dovranno essere vincolate alla procedura di login per poter essere richiamate.
Una volta salvate le modifiche effettuate, potremo avviare il Web server di Rails e visualizzare l’effetto della nuova istruzione; l’immagine seguente mostra per esempio la reazione dell’applicazione in seguito ad un click sul link che dovrebbe consentire l’accesso al form per la modifica di uno specifco record:
Una volta digitate le credenziali richieste, gli esiti dell’operazione potrebbero essere due: se username e password sono corrette, si potrร accedere alla pagina per la modifica del record selezionato, diversamente, l’applicazione segnalerร l’esito negativo del login riproponendo il modulo per l’autenticazione o tramite la seguente notifica di stato:
HTTP Basic: Access denied.
Vale la pena di sottolineare che il Rails server intercetta una procedura di login eseguita con successo notificandola nel modo seguente:
Started GET "/news" for 127.0.0.1 at 2012-05-08 10:24:05 +0200
Processing by NewsController#index as HTML
?[1m?[36mNew Load (0.0ms)?[0m ?[1mSELECT `news`.* FROM `news` ?[0m
Rendered news/index.html.erb within layouts/application (1.0ms)
Completed 200 OK in 15ms (Views: 11.7ms | ActiveRecord: 0.0ms)
Mentre un tentativo di login conclusosi negativamente verrร segnalato in questo modo:
Started GET "/news/7/edit" for 127.0.0.1 at 2012-05-08 10:31:24 +0200
Processing by NewsController#edit as HTML
Parameters: {"id"=>"7"}
Filter chain halted as #<Proc:0x378d6b0@C:/Ruby193/lib/ruby/gems/1.9.1/gems/acti
onpack-3.2.3/lib/action_controller/metal/http_authentication.rb:112> rendered or
redirected
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms)
Lo status code HTTP 200, cioรจ quello relativo alla prima risposta del Rails server, evidenzia il successo della richiesta (“The request was fulfilled“); il codice di stato 401 (“Unauthorized“), quello generato nel secondo caso, indica invece la necessitร di inviare nuovamente la richiesta di autenticazione.