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.

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 è possibile calcolare la radice quadrata usando...

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ร