Introduzione

L'affermazione del Web 2.0 e le sue implicazioni tecnologiche e sociali sono ormai note a tutti noi. MokaByte se ne sta ampiamente occupando nelle sue pagine con una serie di articoli finalizzati a descriverne caratteristiche, soluzioni e ambito di azione. In questo articolo ci occuperemo di Web 2.0 in un'ottica esclusivamente Ruby On Rails. Il presente articolo è suddiviso logicamente in due sezioni:

1. Alcuni esempi di implementazione di soluzioni Rails con una breve premessa relativa ai principi di Ajax. 2. Qualche cenno ad alcuni prodotti, liberamente disponibili, vicini al mondo Web 2.0, realizzati in Rails, che possono essere interessanti punti di riferimento in materia.

Iniziamo dalla prima sezione.

Ajax. The Rails Way

Uno degli strumenti tecnologici che ha consentito l'affermazione del Web 2.0 è, senza dubbio, legato Ajax. La disponibilità di un front-end web, al tempo stesso accattivante ma soprattutto user-oriented, ha dato un notevole impulso all'affermazione del "content user based site". Innanzitutto che cosa è Ajax e a che cosa serve? Facciamo una rapida descrizione. Asynchronous JavaScript and XML, questo il significato dell'acronimo, è una tecnica che permette di estendere le usuali (ormai del Web 1.0) funzionalità nelle applicazioni web ricaricando frammenti della pagina HTML in maniera asincrona, consentendone aggiornamento o sostituzione senza che questa operazione coinvolga l'intera pagina.

Figura 1 - Il modello di classica applicazione web 1.0 e quello di applicazione web 2.0 [fonte Adaptive Path]
Figura 1 - Il modello di classica applicazione web 1.0 e quello di applicazione web 2.0 [fonte Adaptive Path]

La presenza di un Ajax Engine nella versione 2.0 del Web consente una serie di operazioni al tempo stesso utili e accattivanti per l'utente finale. È sufficiente aprire un account su GMail per averne un'idea precisa di quale possa essere il risultato finale dell'operazione. Il risultato più intrigante, derivante dall'utilizzo di Ajax, è una navigazione web "non bloccata" da operazioni di richiesta del browser, cosa questa particolarmente sgradevole al rapido e smaliziato utente Internet.

Figura 2 - Il modello sincrono confrontato con quello asincrono [fonte Adaptive Path]
Figura 2 - Il modello sincrono confrontato con quello asincrono [fonte Adaptive Path]

Ma fin qui abbiamo motivato solo la A di Ajax, cioè Asynchronous.

Passiamo alla Ja = JavaScript. Al fine di gestire le richieste Ajax effettuate dalla pagina web si ricorre al JavaScript e in particolare a determinate librerie che mettono a disposizione una serie di funzionalità (= funzioni) atte a raggiungere lo scopo. In particolare noi utilizzeremo il framework Prototype per i nostri semplici esempi, una libreria che facilita la realizzazione di soluzioni dinamiche.

La X = XML nell'acronimo è motivata più che altro da ragioni storiche poiché non è detto che i dati passati su XMLHttpRequest siano in formato XML.

Aggiungiamo che la comunicazione tra il client e il server avviene ricorrendo a XMLHttpRequest, "...una API che può essere utilizzata in JavaScript, e in altri linguaggi di scripting per trasferire XML e altri formati testo verso e dal web server utilizzando HTTP, realizzando una comunicazione su di un canale indipendente tra la pagina web lato client e la componente server." [Wikipedia].

Ajax è chiaramente utilizzabile da qualsiasi ambiente lato server ma Rails nasce con un supporto built-in. Sviluppare applicazioni basate su RoR che ricorrono largamente ad Ajax è quindi piuttosto semplificato.

Facciamo qualche esempio in merito.

Apriamo Aptana, con il supporto RoR, e creiamo un progetto Rails di nome MokabyteAjax. Tutti gli effetti Ajax e le operazioni DOM disponibili sono contenute nei .js presenti in public/javascript e creati in automatico alla generazione del progetto.

Per renderle disponibili all'interno della componente view è sufficiente effettuare la seguente chiamata nella sezione <head> della pagina .rhtml:

<%= javascript_include_tag("prototype", "effects") %>

Possiamo immettere questa inclusione nella pagina template in modo tale che sia immediatamente disponibile per tutte le pagine che ci fanno riferimento.

In generale per fare una invocazione Ajax si ricorre ad un espressione simile alla seguente:

<%= link_to_remote("Do something", :update => 'myajaxdiv',
  :url => { :action => :actionname }) %>

dove il primo parametro risulta essere il testo del link, il secondo l'elemento (id) della pagina che sarà aggiornato e il terzo è la action che viene invocata. Ovviamente nella view sarà presente qualcosa del tipo:

<div id="myajaxdiv">Something will be changed</div>

Realizziamo un semplice esempio. Creiamo il controller First e l'action index:

ruby script/generate controller First index

Modifichiamo la pagina template app/views/layouts/first.rhtml:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Language" content="en-us" />
  <%= javascript_include_tag "prototype", "effects" %>
  <title>Mokabyte - Rails & Web 2.0</title>
</head>
<body>
  <%= yield %>
</body>
</html>

Nella view app/views/first/index.rhtml inseriamo:

<%= link_to_remote("Do something", :update => 'myajaxdiv', :url => { :action => :dothing }) %>
<div id="myajaxdiv">Something will be changed</div>

Nel controller app/controllers/first_controller.rb aggiungiamo l'action dothing:

def dothing
  render(:text => "<span>(DateTime.now = #{DateTime.now})</span>", :layout => false)
end

A questo punto possiamo fare lo start del nostro server MokabyteAjaxServer ed invocare http://localhost:3000/first/index.

Clicchiamo su "Do something" ed otteniamo qualcosa simile a quanto mostrato in figura 3.

Figura 3 - Risultato dell'invocazione Ajax
Figura 3 - Risultato dell'invocazione Ajax

Passiamo a un esempio un po' più evoluto. Si tratta di una lista di elementi che si aggiorna mediante Ajax, quindi senza ricaricare l'intera pagina ma solo il frammento di interesse. Introduciamo qualche elemento di interesse all'esempio simulando la presenza di una base dati di elementi "da fare" aggiungendo nel model una classe todo.rb (app/models/todo.rb) con il seguente contenuto:

class Todo
  attr_reader :element
  attr_reader :postingTime
  DATABASE = []

  def initialize(element)
    @element = element
    @postingTime = Time.now
    DATABASE.unshift(self)
  end

  def self.find_recent
    DATABASE
  end
end

Nel controller creiamo le action necessarie:

class ListController < ApplicationController
  def add_element
    todo = Todo.new(params[:element_body])
    render(:partial => "todo", :object => todo, :layout => false)
  end

  def index
    @todos = Todo.find_recent
  end
end

Per creare un form Ajax si utilizza l'helper formremotetag:

form_remote_tag(:url => { :action => "actionname" }, :update => "div_to_update")

Nella view app/views/list/index.rhtml definiamo il form e le funzioni JavaScript:

<% content_for("page_scripts") do -%>
  function todo_added() {
    var todo = $('todos').firstChild;
    new Effect.Highlight(todo);
    Element.hide('busy');
    $('form-submit-button').disabled = false;
  }

  function todo_loading() {
    Element.show('busy');
    $('form-submit-button').disabled = true;
  }
<% end -%>

<ul id="todos">
  <%= render(:partial => 'todo', :collection => @todos) %>
</ul>

<%= form_remote_tag(:url => { :action => "add_element" },
  :update => "todos",
  :position => :top,
  :loading => 'todo_loading()',
  :complete => 'todo_added()') %>
  <%= text_field_tag('element_body', '', :id => 'element-body-field') %>
  <%= submit_tag("Add Item", :id => 'form-submit-button') %>
  <span id='busy' style="display: none">Adding my item</span>
<%= end_form_tag %>

Il partial _todo.rhtml contiene:

<li>
  <p>
    <%= todo.postingTime.strftime("%H:%M:%S") %>: <%= todo.element %>
  </p>
</li>

Il template app/views/layouts/list.rhtml:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <%= javascript_include_tag("prototype", "effects") %>
  <script type="text/javascript"><%= @content_for_page_scripts %></script>
  <title>My To Do List</title>
  <%= stylesheet_link_tag 'mokabyte' %>
</head>
<body>
  <h1>My List</h1>
  <%= @content_for_layout %>
</body>
</html>

L'esempio è ora completo e funzionante. Quando l'utente inserisce un nuovo elemento e clicca su "Add Item", la lista viene aggiornata dinamicamente senza ricaricare l'intera pagina.

Conclusioni

In questo articolo abbiamo visto come Ruby on Rails offra un supporto nativo e semplificato per lo sviluppo di applicazioni Web 2.0 basate su Ajax. L'integrazione delle librerie Prototype ed Effects, insieme agli helper forniti dal framework, permette di creare interfacce dinamiche e user-friendly con poche righe di codice.

Rails si conferma quindi una piattaforma ideale per lo sviluppo di applicazioni web moderne, in linea con i paradigmi del Web 2.0.