Microsoft's Internet Explorer browser has no built-in vector graphics machinery required for "loss-free" gradient background themes.

Please upgrade to a better browser such as Firefox, Opera, Safari or others with built-in vector graphics machinery and much more. (Learn more or post questions or comments at the Slide Show (S9) project site. Thanks!)

RubyOnRails

Getting Started

Master "Tecnologie OpenSource"

I Web Frameworks

I framework web sono dei software che permettono di sviluppare e mantenere applicazioni web in modo veloce e semplice.

Questo è possibile grazie all’utilizzo di un architettura software consistente ed all’uso di alcune convenzioni nella metodologia di sviluppo. Lo sviluppatore, attenendosi a tali convenzioni è in grado di produrre, in poco tempo, applicazioni web di alta qualità.

La libertà dello sviluppatore è comunque garantita dalla possibilità di estendere il framework con nuove funzionalità.

Esistono numerosi web framework progettati per sviluppare applicazioni web utilizzando diversi linguaggi di programmazione.

RubyOnRails: Origini e storia

Il framework RubyOnRails (RoR) è stato originariamente ideato e sviluppato da David Heinemeier Hansson.

Il progetto è stato reso opensource nel Luglio del 2004.

Il grande merito di RoR consiste nell’aver introdotto il linguaggio di programmazione Ruby nel mondo dello sviluppo web.

Come altri framework web, RoR basa la propria architettura sul modello (o pattern) MVC (Model View Controller). In questo modello si individuano le tre principali componenti di un’applicazione web.

RubyOnRails: Origini e storia

In generale, il modello (model) rappresenta la componente responsabile di mantenere lo stato dell’applicazione.

La vista (view) espone l’interfaccia utente dell’applicazione web. Ad esempio, un negozio online esporrà, per mezzo di una vista, l’elenco dei prodotti disponibili in magazzino.

Infine, il controller è responsabile della logica di funzionamento dell’applicazione.

RubyOnRails: Origini e storia

  • Convention over Configuration
  • Domain Specific Language
  • ActiveRecord e Migration

Il pattern MVC: i modelli

Come abbiamo visto, il modello rappresenta la componente responsabile di mantenere lo stato dell’applicazione. Ad esempio, all’interno della tabella di un database si registrano le informazioni relative agli utenti che utilizzano l’applicazione web. Nell’ottica del pattern MVC, tale tabella rappresenta un modello.

I sistemi database più diffusi oggi appartengono alla categoria dei database relazionali.

I database relazionali basano il loro principio di funzionamento su una complessa teoria matematica. In effetti, interrogare un database relazionale può risultare, in certi casi, poco agevole.

Inoltre, la teoria dei database relazionali non si coniuga bene con quella della programmazione orientata agli oggetti.

Per questo motivo, è stata sviluppata delle soluzioni (Design Pattern) che consente di mettere in relazione le tabelle di un database relazionale con le classi di un’applicazione orientata agli oggetti. Il nome di questo design pattern è Object Relational Mapping (ORM).

Il pattern MVC: le viste

Le viste (views) sono responsabili della creazione dell’interfaccia utente che l’applicazione web espone all’utente.

Ad esempio, in una tipica applicazione web, le viste si occupano di generare le pagine web contenenti i moduli di inserimento (form) dati, i contenuti, i risultati di una ricerca, etc.

In RoR la generazione delle viste avviene in maniera dinamica. Questo significa che la vista viene generata a partire dalla struttura della pagina (layout), “riempita” dalle informazioni dinamiche generate in tempo reale.

Il pattern MVC: le viste

Il framework RoR mette a disposizione diverse tecnologie di generazione dinamica delle viste. Le più utilizzate sono:

ERB permette di iniettare degli snippet di codice ruby all’interno di codice HTMl per generare i contenuti dinamici delle viste.

Builder è una libreria inclusa in RoR che permette di generare documenti XML attraverso un DSL (Domain Specific Language) ruby.

Il pattern MVC: i controller

I controller di un’applicazione RoR gestiscono la cosidetta logica della stessa.

In particolare, il controller coordina l’interazione tra l’utente, le viste e i modelli.

Inoltre, il controller è responsabile

Il pattern MVC: i controller

La Business Logic nel limite del possibile… va inserita nei Modelli!!!

Installazione e configurazione dell’ambiente: Ruby e Rubygems

Per iniziare a sviluppare un’applicazione web RoR occorrono pochi semplici passi.

Gran parte del processo di installazione è infatti gestito dal package manager del sistema Ubuntu (apt) e dal package manager di ruby (rubygems).

L’installazione dell’interprete ruby si riduce all’esecuzione del seguente comando:

andrea@ganimoide:~$ sudo apt-get install ruby ruby-dev ri rdoc \
		    	 libopenssl-ruby

Installazione e configurazione dell’ambiente: Ruby e Rubygems

Per quanto riguarda l’installazione di Rubygems occorre prima scaricare e decomprimere il tarball dell’applicazione:

andrea@ganimoide:~$ wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
andrea@ganimoide:~$ tar xvzf rubygems-1.3.1.tgz

A questo punto occorrerà eseguire lo script setup.rb all’interno della cartella rubygems:

andrea@ganimoide:~$ cd rubygems-1.3.1 && sudo ruby setup.rb

Installazione di RubyOnRails

Una volta installato l’interprete ruby e il package manager rubygems, l’installazione di RoR si riduce all’esecuzione di un solo comando:

andrea@ganimoide:~$ sudo gem install rails

Il comando gem install rails risolve ed installa tutti i pacchetti (gemme) da cui il framework RoR dipende.

Per verificare la corretta installazione di RoR basterà eseguire:

andrea@ganimoide:~$ rails --version
Rails 2.3.2

Installazione di RubyOnRails

RoR supporta diversi tipi di motori database, tra cui:

Nella slide precedente abbiamo visto come RoR supporti diversi database.

Tuttavia, la configurazione standard del framework prevede l’utilizzo di SQLite3.

Installazione di RubyOnRails

Se sul sistema in uso non è presente SQLite3, sarà sufficiente installare le librerie C da apt e quelle ruby da rubygems

andrea@ganimoide:~$ sudo apt-get install libsqlite3-0 libsqlite3-dev
[...]
andrea@ganimoide:~$ sudo gem install sqlite3-ruby
[...]

A questo punto l’ambiente RoR è completamente installato e configurato e possiamo procedere alla creazione della nostra prima applicazione.

Hello Rails: generare l’applicazione

Per generare la nostra prima applicazione RoR ci serviamo del comando rails:

andrea@ganimoide:~/src$ rails demo
      create  
      create  app/controllers
      create  app/helpers
      create  app/models
      create  app/views/layouts
      create  config/environments
      create  config/initializers
      create  config/locales
      create  db
      create  doc
      create  lib
...

Hello Rails: generare l’applicazione

Il comando rails necessita di un solo argomento: il nome della cartella all’interno della quale vogliamo generare lo scheletro della nostra applicazione RoR.

Come si vede, il generatore si occupa di creare una struttura adeguata a contenere le varie componenti della nostra applicazione tra cui le viste, i modelli, i controller, i file di configurazione, i file di log, il database.

Hello Rails: eseguire il webserver

Il webserver è la componente che si occupa di raccogliere le richieste http proveniente dall’esterno, instradarle verso l’applicazione RoR e trasmettere le risposte ottenute.

RoR supporta diversi webserver tra cui:

Hello Rails: eseguire il webserver

In questi nostri primi esperimenti utilizzeremo webrick il webserver integrato in RoR. Questa scelta ci offre notevoli vantaggi in termini di semplicità d’uso. Infatti, per eseguire il webserver e ottenere immediatamente un ambiente di sviluppo funzionante basterà eseguire lo script server:

andrea@ganimoide:~/src/demo$ ruby script/server 
=> Booting WEBrick
=> Rails 2.3.2 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2009-04-06 19:57:24] INFO  WEBrick 1.3.1
[2009-04-06 19:57:24] INFO  ruby 1.8.7 (2008-08-11) [i486-linux]
[2009-04-06 19:57:29] INFO  WEBrick::HTTPServer#start: pid=11126 port=3000

Hello Rails: visualizzare l’applicazione

Nella precedente slide abbiamo visto come eseguire il webserver webrick. Riportiamo l’ultima linea di log della slide precedente:

...
[2009-04-06 19:57:29] INFO  WEBrick::HTTPServer#start: pid=11126 port=3000
...

Come si vede, webrick ci informa che il webserver è in ascolto sulla porta 3000.

A questo punto, eseguendo un qualsiasi browser (ad esempio firefox), basterà visitare l’url:

http://localhost:3000

per vedere la nostra prima applicazione in esecuzione.

In realtà, l’applicazione visualizzerà solo la pagina dimostrativa standard.

Tuttavia, lo scheletro ci fornisce un buon punto di partenza per personalizzare il nostro software.

Hello Rails: creare un nuovo controller

Per creare il nostro primo controller ci serviremo di un’utile funzionalità di RoR: i generatori.

Per mezzo dei generatori è possibile creare in maniera programmatica parte del codice della nostra applicazione.

Per generare un controller di nome Say eseguiamo:

andrea@ganimoide:~/src/demo$ ruby script/generate controller Say
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/say
      exists  test/functional/
      create  test/unit/helpers/
      create  app/controllers/say_controller.rb
      create  test/functional/say_controller_test.rb
      create  app/helpers/say_helper.rb
      create  test/unit/helpers/say_helper_test.rb

Hello Rails: creare un nuovo controller

Come si vede, RoR si occupa di creare automaticamente il file contenente il codice del controller (app/controllers/say_controller.rb) e una serie di file ad esso correlati.

Visualizzando il contenuto del file say_controller.rb ci rendiamo conto che esso è alquanto minimale!

andrea@ganimoide:~/src/demo$ cat app/controllers/say_controller.rb 
class SayController < ApplicationController
end

Hello Rails: Routing e azioni

Il controller Say così com’è non serve a molto! Infatti, esso non implementa alcuna funzionalità.

Per dare vita al nostro controller dobbiamo implementare delle azioni (action). Le action sono le risposte del controller a particolari richieste.

Al fine di instradare nel modo corretto le richieste verso il controller che può soddisfarle, RoR utilizza alcune convenzioni sugli indirizzi.

Hello Rails: Routing e azioni

Immaginiamo di far puntare il nostro browser al seguente indirizzo:

http://localhost:3000/say/hello

Tale URL verrà interpretato da RoR come una richiesta verso il controller Say. In particolare, al controller viene richiesto di eseguire l’azione hello.

Nello specifico, hello è un metodo di istanza del controller Say. La nostra prima implementazione ingenua potrebbe essere:

class SayController < ApplicationController
  def hello
  end
end

Hello Rails: Implementare una vista

Nella precedente slide abbiamo implementato la nostra prima azione. Ora eseguiamo il browser e visitiamo l’indirizzo

http://localhost:3000/say/hello

Come si potrà verificare, il framework ci segnala un errore nel tentativo di visualizzare la pagina. Lo stesso errore è riportato nell’output della console all’interno della quale abbiamo eseguito il webserver.

Hello Rails: Implementare una vista

L’errore in questione ci segnala l’assenza della vista collegata all’azione che abbiamo richiesto (cioè SayController#hello).

Per rimediare a questo problema dobbiamo creare il file hello.erb nella cartella app/view/say:

<html>
  <head>
    <title>Hello Rails!</title>
  </head>
  <body>
    <p>Hello Rails</p>
  </body>
</html>

Terminata la stesura del file hello.erb provate a ricaricare la pagina. Se visualizzate il testo ‘Hello Rails!’ allora avete creato la vostra prima applicazione RoR!

Hello Rails: Implementare una vista

Ma quella di prima è una semplice pagina HTML statica, direte voi. Vale la pena scomodare un framework come RoR per realizzare semplici pagine HTML?

Ovviamente no, il bello deve ancora arrivare. Proviamo ad aggiungere un pizzico di dinamicità alla nostra precedente pagina.

<html>
  <head>
    <title>Hello Rails!</title>
  </head>
  <body>
    <p>Hello Rails</p>
    <p>Data e ora: <%= Time.now %></p>
  </body>
</html>

Hello Rails: Implementare una vista

Come si potrà verificare, la modifica apportata sopra realizza una vista in grado di visualizzare la data e l’ora attuali.

Come avviene la stampa dinamica di queste informazioni? La risposta è erb (Embedded Ruby).

In pratica, RoR è in grado di generare viste con all’interno codice ruby.

Il codice ruby viene inserito all’interno della sequenza di caratteri <% %>

Nell’esempio il codice in questione è Time.now. Provate ad eseguirlo all’interno di una console ruby.

Hello Rails: collegare fra loro le pagine

Normalmente, un’applicazione web è costituita da più di una pagina web. Come gestisce RoR il collegamento tra le diverse pagine?

Creiamo una seconda vista goodbye.erb nella cartella views/say:

<html>
  <head>
    <title>Ciao ciao!</title>
  </head>
  <body>
    <p>A presto! E' stato un piacere conoscerti!</p>
  </body>
</html>

Hello Rails: collegare fra loro le pagine

Ora, associamo la visualizzazione della nuova vista all’azione SayController#goodbye:

class SayController < ApplicationController
  def hello
  end
  def goodbye
  end
end

Infine, proviamo a visualizzare il risultato della richiesta say/goodbye sul browser visitando il link:

http://localhost:3000/say/goodbye

Se tutto è andato per il verso giusto dovremmo visualizzare una pagina di commiato.

Hello Rails: collegare fra loro le pagine

Come collegare la vista hello.erb alla vista goodbye.erb?

Niente di più semplice:

<html>
  <head>
    <title>Hello Rails!</title>
  </head>
  <body>
    <p>Hello Rails</p>
    <p>Data e ora: <%= Time.now %>
    <p>Ops.. E' già ora di dirci <%= link_to 'ciao..', :action => 'goodbye' %>
  </body>
</html>

Il metodo link_to eseguito all’interno della sequenza <% %> è un helper method. Esso rappresenta un modo semplice e veloce di generare collegamenti ad altre viste attraverso le azioni ad esse associate.

Hello Rails: Separare le viste dalla logica di funzionamento

Nella vista hello.erb visualizziamo la data e l’ora eseguento il methodo di classe Time::now.

Dal punto di vista operativo questa procedura non è errata. In effetti, il risultato è quello voluto.

Tuttavia, dal punto di vista concettuale questa non è una procedura corretta.

Richiamando il metodo Time::now stiamo vincolando la vista ad un dettaglio implementativo. Se, infatti, volessimo localizzare la visualizzazione della data e dell’ora in funzione della provenienza dell’utente, dovremmo aggiungere ulteriori aspetti implementativi all’interno della vista.

Questa non è una cosa buona, in quanto le viste dovrebbero occuparsi esclusivamente dell’interfaccia da esporre all’utente.

Hello Rails: Separare le viste dalla logica di funzionamento

Spostando la logica di funzionamento sul lato controller, possiamo risolvere questo inconveniente:

class SayController < ApplicationController
...
  def hello
    @time = Time.now
  end
...
end

Esercizio: Modificate la vista hello.erb in modo da utilizzare la nuova implementazione dell’azione SayController#hello.

Lo sviluppo guidato da test

Supponete di avere in mente una nuova, sbrilluccicante, funzionalità da aggiungere alla vostra prima applicazione RoR. Quale sarà la vostra prima tentazione? Probabilmente quella di modificare il controller SayController aggiungendo nuove azioni!

Quindi, da bravi sviluppatori, vi affretterete a testare il corretto funzionamento della nuova funzionalità scrivendo un po’ di codice di test.

Agireste così? No? Tranquilli, sareste in buona compagnia. Questa è infatti la procedura che seguirebbe il 90% degli sviluppatori al mondo [e che di fatto abbiamo utilizzato ed utilizzeremo anche noi per i nostri semplici esempi].

Lo sviluppo guidato da test

E se invertissimo il processo? Cioè, se prima scrivessimo i test e dopo andassimo ad implementare la nuova funzionalità?

In tal caso staremmo utilizzando una metodologia di sviluppo nota come TDD (Test Driven Development).

Citiamo alcuni dei vantaggi insiti in questo approccio:

Lo sviluppo guidato da test

Come si traducono in codice le considerazioni fatte nella precedente slides?

Supponiamo di voler aggiungere alla nostra applicazione una nuova funzionalità. Quando l’utente richiede l’esecuzione dell’azione hello, l’applicazione deve essere in grado di produrre un messaggio di saluto contenente il nome dell’utente autenticato.

Per far ciò è necessario che il controller acquisisca l’informazione sul nome dell’utente. Nella realtà, quest’informazione sarebbe contenuta all’interno della tabella di un database.

Per prima cosa scriviamo il test.

Lo sviluppo guidato da test

Cosa ci aspettiamo quando eseguiamo l’azione SayController#hello? Ci aspettiamo che essa abbia accesso ad una variabile d’instanza user contenente il nome dell’utente. Tale variabile non deve contenere il valore nil:

class SayControllerTest < ActionController::TestCase
  test "username is not nil" do
    get :hello
    assert_not_nil assigns(:user)
  end
end

Il metodo get effettua la richiesta di esecuzione dell’azione hello.

Il metodo assert_not_nil verifica che la variabile user non contenga il valore nil.

Lo sviluppo guidato da test

Se proviamo ad eseguire il test attraverso il task test:

andrea@ganimoide:~/src/demo/rake test

Domanda: Vi aspettate che il test abbia successo?

Lo sviluppo guidato da test

Ovviamente, il test proposto nella precedente slide fallisce perché dobbiamo ancora implementare la nuova funzionalità.

class SayController < ApplicationController
...
  def hello
    @user = 'Utente'
    @time = Time.now
  end
...
end

Nella realtà il nome dell’utente da assegnare alla variabile d’istanza user sarebbe immagazzinato all’interno di una tabella di un database.

Nel nostro esempio, allo scopo di semplificare la trattazione, assegneremo staticamente un valore alla variabile.

Lo sviluppo guidato da test

La nostra implementazione è corretta? Eseguiamo nuovamente i test per fare una verifica:

andrea@ganimoide:~/src/demo/rake test
...
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
Started
.
Finished in 0.062932 seconds.

1 tests, 1 assertions, 0 failures, 0 errors
...

I risultati del test sono positivi. La nostra implementazione è corretta: la variabile d’istanza user contiene un valore diverso da nil.

Copyright (C) 2008 - Alca Societa' Cooperativa

http://alca.le.it - info@alca.le.it

released under CreativeCommons 2.5 by-nc-sa

NOTA: le immagini dei software e dei device contenuti
nella presentazione sono proprieta' dei relativi detentori
del copyright e sono state riprodotte a scopo esclusivamente didattico.