back to top

Iniziare a sviluppare con Ruby on Rails

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.

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.

Installare RoR su Windows

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:

localhost di RoR

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:

  1. "development": รจ lโ€™ambiente destinato allo sviluppo locale dellโ€™applicazione prima delle fasi di test e di produzione (messa on-line);
  2. "test": รจ lโ€™ambiente utilizzabile in seguito alla fase di sviluppo per lโ€™esecuzione dei test automatizzati sullโ€™applicazione prima della fase di produzione;
  3. "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:

  1. "index.html.erb": rappresenta la View relativa alla visualizzazione di tutti i record;
  2. "new.html.erb": presenta il form per lโ€™inserimento di un nuovo record;
  3. "show.html.erb": mostra un singolo record e fornisce i collegamenti per la sua manipolazione;
  4. "_form.html.erb": contiene il form che verrร  utilizzato per le operazioni di editing;
  5. "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.

Altri contenuti interessanti

Pubblicitร 
Claudio Garau
Claudio Garau
Web developer, programmatore, Database Administrator, Linux Admin, docente e copywriter specializzato in contenuti sulle tecnologie orientate a Web, mobile, Cybersecurity e Digital Marketing per sviluppatori, PA e imprese.

Leggi anche...

Radice quadrata in C: vediamo come calcolarla in diversi modi

La radice quadrata รจ un'operazione matematica piuttosto comune (in...

Sperimentare la sequenza di Collatz in C++

Vediamo come verificare la congettura di Collatz con C++....

Calcolare la radice quadrata con Python

In Python, calcolare la radice quadrata รจ un'operazione piuttosto...

12 film che ogni programmatore dovrebbe guardare (per trovare ispirazione e creativitร )

Molti ragazzi hanno deciso di intraprendere una carriera da...

Cartonizzare una foto con Python e la libreria OpenCV

La cartoonization รจ una procedura grafica che consente di...

Creare flowchart (diagrammi di flusso) online: 5 strumenti gratuiti

Hai bisogno di realizzare una flow chart ma non...
Pubblicitร