<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ASCIIcasts - Full Episode Feed</title>
    <description>The latest episodes from ASCIIcasts</description>
    <link>http://asciicasts.com/</link>
    <pubDate>Sun, 14 Aug 2011 05:47:33 +0000</pubDate>
    <ttl>1440</ttl>
    <item>
      <title>Eredietarit&#224; dei template</title>
      <description>&lt;p&gt;Una delle nuove features di Rails 3.1 &amp;egrave; l&amp;rsquo;eredietarit&amp;agrave; dei template. Questa non rivoluzioner&amp;agrave; il modo in cui scrivi le tue views, ma pu&amp;ograve; risultare molto utile e in questo episodio ti mostreremo come funziona.&lt;/p&gt;

&lt;p&gt;In questo episodio abbiamo una applicazione con lo stesso menu di navigazione in ogni pagina.&lt;/p&gt; 

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/670/original/E269I01.png" width="801" height="345" alt="La home page della nostra applicazione"/&gt;
&lt;/div&gt;

&lt;p&gt;Il menu di navigazione &amp;egrave;  al momento definito nel file di layout dell&amp;rsquo;applicazione dentro un elemento &lt;code&gt;div&lt;/code&gt; con &lt;code&gt;id&lt;/code&gt; uguale a &lt;code&gt;side&lt;/code&gt; ed &amp;egrave; statico.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Store&amp;lt;/title&amp;gt;
  &amp;lt;%= stylesheet_link_tag &amp;quot;application&amp;quot; %&amp;gt;
  &amp;lt;%= javascript_include_tag &amp;quot;application&amp;quot; %&amp;gt;
  &amp;lt;%= csrf_meta_tags %&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;

    &amp;lt;% flash.each do |name, msg| %&amp;gt;
      &amp;lt;%= content_tag :div, msg, :id =&amp;gt; &amp;quot;flash_#{name}&amp;quot; %&amp;gt;
    &amp;lt;% end %&amp;gt;

    &amp;lt;div id=&amp;quot;side&amp;quot;&amp;gt;
      &amp;lt;strong&amp;gt;Pages&amp;lt;/strong&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Home&amp;quot;, root_path %&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Products&amp;quot;, products_path %&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;%= yield %&amp;gt;

    &amp;lt;div class=&amp;quot;clear&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;Vogliamo personalizzare il men&amp;ugrave; in maniera tale cha cambi in base all&amp;rsquo;attuale controller . Esistono diversi modi per fare questo e noi useremo l&amp;rsquo;ereditariet&amp;agrave; dei template. Per prima cosa spostiamo il men&amp;ugrave; in un partial chiamato &amp;ldquo;side&amp;rdquo;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/layouts/views/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;div id=&amp;quot;side&amp;quot;&amp;gt;
  &amp;lt;%= render &amp;quot;side&amp;quot; %&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;p&gt;Dove dovremmo mettere questo partial in modo tale che qualunque controller possa usarlo? Potremmo metterlo dentro la cartella &lt;code&gt;views/shared&lt;/code&gt; oppure dentro &lt;code&gt;layouts&lt;/code&gt; ma in Rails 3.1 possiamo salvarlo invece dentro &lt;code&gt;views/application&lt;/code&gt;. Questa cartella non esiste di default con Rails 3, dobbiamo quindi crearla.&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/app/views/application/_side.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;strong&amp;gt;Pages&amp;lt;/strong&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Home&amp;quot;, root_path %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Products&amp;quot;, products_path %&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;

&lt;p&gt;Il partial &lt;code&gt;side&lt;/code&gt; pu&amp;ograve; ora essere utilizzato da tutti i controller perch&amp;egrave; l&amp;rsquo;ereditariet&amp;agrave; delle views funziona allo stesso modo di quella dei controller. Tutti i controller ereditano da &lt;code&gt;ApplicationController&lt;/code&gt; quindi tutti i template che si trovano nella cartella &lt;code&gt;application&lt;/code&gt; saranno ereditati.&lt;/p&gt;

&lt;p&gt;Se adesso carichiamo una delle pagine della nostra applicazione il menu di navigazione funziona come prima.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/671/original/E269I02.png" width="801" height="345" alt="Il men&amp;ugrave; di navigazione funziona come prima."/&gt;
&lt;/div&gt;

&lt;p&gt;Abbiamo adesso un partial che possiamo facilmente sovrascrivere in qualunque controller. Per fare questo bisogna creare un file chiamato &lt;code&gt;_side.html.erb&lt;/code&gt; nella cartella &lt;code&gt;views&lt;/code&gt; del controller in questione. Faremo questo per &lt;code&gt;ProductsController&lt;/code&gt;, creando un partial contenente un link in pi&amp;ugrave;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/products/_side.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;strong&amp;gt;Pages&amp;lt;/strong&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Home&amp;quot;, root_path %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Products&amp;quot;, products_path %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Manage Products&amp;quot;, admin_products_path %&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;

&lt;p&gt;Caricando qualunque pagina del &lt;code&gt;ProductsController&lt;/code&gt; il nuovo link sar&amp;agrave; visibile, mentre tutti gli altri controller continueranno ad usare il men&amp;ugrave; di default.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/672/original/E269I03.png" width="801" height="345" alt="Tutte le azione del ProductsController utilizzeranno ora il nuovo template."/&gt;
&lt;/div&gt;

&lt;p&gt;Abbiamo adesso un posto dove salvare i templates che saranno condivisi da tutti i controller e possiamo sovrascrivere ciascuno di essi creando un template con lo stesso nome nella cartella &lt;code&gt;views&lt;/code&gt; del controller desiderato.&lt;/p&gt;

&lt;p&gt;Questo approccio funziona anche con controller annidati. La nostra applicazione ha diversi controller sotto il namespace &lt;code&gt;Admin&lt;/code&gt;, ciascuno dei quali eredita da &lt;code&gt;BaseController&lt;/code&gt;.&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/app/controllers/admin/base_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;module Admin
  class BaseController &amp;lt; ApplicationController
  end
end&lt;/pre&gt;

&lt;p&gt;Possiamo sovrascrivere anche i templates che si trovano in &lt;code&gt;Base&lt;/code&gt; view. Se clicchiamo il link &amp;ldquo;Manage Products&amp;rdquo; nella pagina di sopra ci sposteremo nella pagina &lt;code&gt;/admin/products&lt;/code&gt; e il men&amp;ugrave; di navigazione sar&amp;agrave; di nuovo quello di default. Cosa dovremmo fare se volessimo sovrascrivere il men&amp;ugrave; per tutte le pagine di amministrazione?&lt;/p&gt;

&lt;p&gt;Dentro &lt;code&gt;/app/views/admin&lt;/code&gt; troviamo la cartella &lt;code&gt;base&lt;/code&gt;. Possiamo salvare dei templates qui e questi saranno automaticamente ereditati dagli altri controller. Faremo questo aggiungendo un link per distinguere questo template dagli altri.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/admin/base/_side.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;strong&amp;gt;Pages&amp;lt;/strong&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Home&amp;quot;, root_path %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Products&amp;quot;, products_path %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Manage Products&amp;quot;, admin_products_path %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= link_to &amp;quot;Manage Categories&amp;quot;, admin_categories_path %&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;

&lt;p&gt;Se ricarichiamo la pagina &lt;code&gt;admin/products&lt;/code&gt; vedremo applicato il template  dalla cartella &lt;code&gt;base&lt;/code&gt;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/673/original/E269I04.png" width="801" height="358" alt="Pagine che ereditano da BaseController utilizzeranno adesso i template dalla cartella base."/&gt;
&lt;/div&gt;

&lt;p&gt;Questo template sar&amp;agrave; utilizzato in tutte le pagine del namespace &lt;code&gt;Admin&lt;/code&gt; poich&amp;egrave; queste ereditano dal &lt;code&gt;BaseController&lt;/code&gt; del namespace &lt;code&gt;Admin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;L&amp;rsquo;ereditariet&amp;agrave; dei template funziona non solo per i partial ma per qualunque template view. Nella cartella &lt;code&gt;app/views/admin&lt;/code&gt; c&amp;rsquo;&amp;egrave; un template &lt;code&gt;edit.html.erb&lt;/code&gt; per entrambe le cartelle &lt;code&gt;categories&lt;/code&gt; e &lt;code&gt;products&lt;/code&gt;. Entrambe contengono lo stesso codice.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/admin/categories/edit.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Edit&amp;lt;/h1&amp;gt;

&amp;lt;%= render &amp;#x27;form&amp;#x27; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Se spostiamo uno di questi template nella cartella &lt;code&gt;base&lt;/code&gt; e rimuoviamo l&amp;rsquo;altro, entrambi i controller erediteranno dallo stesso. Entrambe le pagine funzionano nella stessa maniera di prima. Questo &amp;egrave; molto utile nel caso in cui la nostra applicazione contiene molte pagine di amministrazione. Di solito queste pagine hanno molte cose in comune e usando questa tecnica possiamo astrarre i templates in un controller di base e sovrascriverli se necessario.&lt;/p&gt;

&lt;p&gt;E siccome stiamo parlando di come &amp;egrave; possibile sovrascrivere templates, ti mostreremo un altro trucco che ti permette di personalizzare templates in base a dei parametri. Ammettiamo che vogliamo fornire una versione mobile del sito usando il sottodominio &lt;code&gt;mobile&lt;/code&gt;.  Potremmo cambiare le views in base al sottodominio e analizzando l&amp;rsquo;url.  Questa feature non &amp;egrave; nuova in Rails 3.1 e funziona anche in Rails 2 ma siccome si sposa bene con l&amp;rsquo;argomento ne parleremo adesso.&lt;/p&gt;

&lt;p&gt;Nei controller dell&amp;rsquo;applicazione abbiamo qualcosa chiamato view paths. Se chiamiamo &lt;code&gt;controller.view_paths&lt;/code&gt; in una view possiamo vedere quale sia il cammino per le views di quel controller.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/admin/base/edit.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Edit&amp;lt;/h1&amp;gt;

&amp;lt;%= render &amp;#x27;form&amp;#x27; %&amp;gt;

&amp;lt;%= controller.view_paths %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Se ricarichiamo la pagina troveremo la lista delle &lt;code&gt;view_paths&lt;/code&gt;. (Per facilitare l&amp;rsquo;uso di sottodomini  stiamo usando &lt;a href="http://pow.cx/"&gt;Pow web server&lt;/a&gt; durante lo sviluppo della nostra applicazione.)&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/674/original/E269I05.png" width="800" height="405" alt="La pagina mostra tutti i view_paths."/&gt;
&lt;/div&gt;

&lt;p&gt;Questo controller ha una view path di default ma possiamo aggiungerne altre. Un modo per aggiungerne una &amp;egrave; usare un &lt;code&gt;before_filter&lt;/code&gt; nel nostro &lt;code&gt;ApplicationController&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/application_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class ApplicationController &amp;lt; ActionController::Base
  protect_from_forgery
  before_filter :subdomain_view_path
  
  def subdomain_view_path
    if request.subdomain.present?
      prepend_view_path &amp;quot;app/views/#{request.subdomain}_subdomain&amp;quot;
    end
  end  
end&lt;/pre&gt;

&lt;p&gt;Nel metodo &lt;code&gt;before_filter&lt;/code&gt; abbiamo usato &lt;code&gt;&lt;a href="http://apidock.com/rails/AbstractController/ViewPaths/ClassMethods/prepend_view_path"&gt;prepend_view_path&lt;/a&gt;&lt;/code&gt; per aggiungere una nuova view path in base al sottodominio della richiesta, se questo &amp;egrave; presente. Possiamo vedere la nuova view path ricaricando la pagina.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/675/original/E269I06.png" width="800" height="405" alt="La nuova view_path viene adesso visualizzata."/&gt;
&lt;/div&gt;

&lt;p&gt;Il sottodominio mobile viene adesso incluso nella lista delle &lt;code&gt;view_paths&lt;/code&gt;. Se rimuoviamo il sottodominio &lt;code&gt;mobile&lt;/code&gt; dall&amp;rsquo; URL di sopra e ricarichiamo la pagina, questo scomparir&amp;agrave; anche dalla lista delle view_paths. Questo trucco pu&amp;ograve; essere usato per personalizzare le views in base al sottodominio. Se creiamo una nuova cartella sotto &lt;code&gt;views&lt;/code&gt; e la chiamiamo &lt;code&gt;mobile_subdomain&lt;/code&gt; possiamo aggiungervi view templates che sovrascrivono i template di default. Creeremo un nuovo &lt;code&gt;index.html.erb&lt;/code&gt; template dentro la nuova cartella &lt;code&gt;products&lt;/code&gt; e questo template sar&amp;agrave; usato solo in questa pagina quando il sottodominio mobile viene visitato.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/mobile_subdomain/products/index.html&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;mobile version&amp;lt;/h1&amp;gt;&lt;/pre&gt;

&lt;p&gt;Se rimuoviamo il sottodominio vedremo di nuovo la version di default.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/676/original/E269I07.png" width="800" height="323" alt="Senza il sottodominio viene usata la versione di default."/&gt;
&lt;/div&gt;

&lt;p&gt;Tuttavia quando aggiungiamo il sottodominio il  nuovo template viene utilizzato sovrascrivendo quello di default.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/677/original/E269I08.png" width="800" height="280" alt="Il template mobile viene utilizzato se la pagina viene visualizzata nel sottodominio mobile."/&gt;
&lt;/div&gt;

&lt;p&gt;Questo &amp;egrave; tutto per questo episodio su come sovrascrivere i template, sia nel caso in cui sia fatto con l&amp;rsquo;ereditariet&amp;agrave; che in quello in cui il cammino della richiesta venga analizzato. Entrambi i metodi forniscono molte possibilit&amp;egrave; di personalizzazione e diversi metodi per astrarre views e sovrascriverle. Se hai bisogno di ancora pi&amp;ugrave; personalizzazione puoi creare un view resolver ma parleremo di questo in un altro episodio.&lt;/p&gt;</description>
      <pubDate>Tue, 21 Jun 2011 18:30:46 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/269-eredietarita-dei-template</guid>
      <link>http://it.asciicasts.com/episodes/269-eredietarita-dei-template</link>
    </item>
    <item>
      <title>Concetti base in SASS</title>
      <description>&lt;p&gt;Uno dei maggiori cambiamenti con il nuovo Rails 3.1 &amp;egrave; il supporto per &lt;a href="http://sass-lang.com/"&gt;SASS&lt;/a&gt;, il quale rappresenta la soluzione di default per generare CSS. Grazie a concetti come annidamento, variabili e molto altro ancora, gestire lo stile della vostra applicazione diventa molto pi&amp;ugrave; semplice. Per dimostrare i vantaggi che comporta usare SASS, in questo episodio mostreremo come tradurre il CSS di una applicazione esistente in SASS.&lt;/p&gt;

&lt;p&gt;Il sito su cui lavoreremo si presenta cos&amp;igrave;:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/665/original/E268I01.png" width="801" height="381" alt="La nostra applicazione."/&gt;
&lt;/div&gt;

&lt;p&gt;Tutto lo stile &amp;egrave; realizzato utilizzando CSS, il nostro obiettivo &amp;egrave; mantenere lo stesso stile una volta finita la migrazione. Questo &amp;egrave; il file su cui lavoreremo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css&lt;/p&gt;
&lt;pre class="css"&gt;body {
  margin: 0;
  padding: 0;
  background-color: #FFF;
  font-family: verdana;
  font-size: 14px;
}

#header {
  background-color: #03507B;
  color: #FFF;
  padding: 4px 100px;
  border-bottom: solid 5px #00395A;
}

#header h1 {
  font-size: 30px;
}

a {
  color: #03507B;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

.new_project {
  background-color: #03507B;
  color: #FFF;
  padding: 5px 12px;
  margin: 10px 0;
  font-size: 16px;
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}
#container { 
  margin: 0 100px; 
}

.project {
  border: solid 1px #777;
  margin: 20px 0;
  padding: 7px 12px;
  border-radius: 10px;
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;
}

.project h2 { 
  margin: 0; 
}&lt;/pre&gt;

&lt;p&gt;Questo file &amp;egrave; abbastanza semplice quindi il nostro compito non dovrebbe essere molto difficile.Per prima cosa bisogna rinominare il file aggiungendo l'estensione &lt;code&gt;.scss&lt;/code&gt;. Standard CSS &amp;egrave; completamente compatibile con SASS quindi ricaricando il browser tutto dovrebbe essere rimasto invariato.&lt;/p&gt;

&lt;p&gt;Il nostro sito usa gi&amp;agrave; SASS, ma ovviamente non &amp;egrave; tutto qui. &amp;Egrave; comunque ottimo il fatto che CSS &amp;egrave; completamente supportato poich&amp;egrave; questo ci permette di scegliere solo le funzionalit&amp;agrave; che ci interessano. Se abbiamo un sito con un gran numero di CSS gi&amp;agrave; esistenti possiamo rinominarli e modificarli quando e come vogliamo. Ma considerando quello che vi stiamo per mostrare probabilmente vorrette usare tutto immediatemente.&lt;/p&gt;

&lt;h3&gt;Annidamento&lt;/h3&gt;

&lt;p&gt;La prima funzionalit&amp;agrave; che useremo &amp;egrave; annidiamento. Guarda questo codice CSS:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;#header {
  background-color: #03507B;
  color: #FFF;
  padding: 4px 100px;
  border-bottom: solid 5px #00395A;
}

#header h1 { 
  font-size: 30px; 
}&lt;/pre&gt;

&lt;p&gt;Questo codice definisce lo stile per un element con &lt;code&gt;id&lt;/code&gt; uguale a header e per ogni elemento &lt;code&gt;h1&lt;/code&gt; in esso contenuto. Con SASS possiamo annidare lo stile per &lt;code&gt;h1&lt;/code&gt; dentro quello per &lt;code&gt;#header&lt;/code&gt; cos&amp;igrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;#header {
  background-color: #03507B;
  color: #FFF;
  padding: 4px 100px;
  border-bottom: solid 5px #00395A;

	h1 { 
		font-size: 30px; 
	}
}&lt;/pre&gt;

&lt;p&gt;Quindi non abbiamo pi&amp;ugrave; bisogno di specificare il prefisso per elementi interni e siamo anche incoraggiati a mantenere compatto lo stile per elementi annidati. Pu&amp;ograve; risultare semplice abusare di questa funzionalit&amp;agrave; introducento annidamenti lunghi e complessi ma &amp;egrave; meglio invece mantenere il nostro annidamento semplice. In questa maniera baster&amp;agrave; un'occhiata per capire cosa &amp;egrave; dentro cosa. Questa non &amp;egrave; comunque una regola e puoi trovare e usare il livello di annidamento che si adatta meglio ai tuoi gusti.&lt;/p&gt;

&lt;p&gt;Possiamo anche usare annidimento auto-referenziale. Nel CSS abbiamo un selector per &lt;code&gt;a&lt;/code&gt; ed uno per &lt;code&gt;a:hover&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;a {
  color: #03507B;
  text-decoration: none;
}

a:hover { 
  text-decoration: underline;
}&lt;/pre&gt;

&lt;p&gt;Poich&amp;egrave; &lt;code&gt;a:hover&lt;/code&gt; non &amp;egrave; un vero e proprio elemento annidato dobbiamo aggiungere una &amp;amp; al padre.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;a {
  color: #03507B;
  text-decoration: none;

  &amp;amp;:hover { 
   text-decoration: underline;
  }
}&lt;/pre&gt;

&lt;p&gt;La &amp;amp; &amp;egrave; necessaria perch&amp;egrave; stiamo applicando stile a un attributo e non ad un vero e proprio elemento.&lt;/p&gt;

&lt;h3&gt;Variabili&lt;/h3&gt;

&lt;p&gt;Un' altra funzionalit&amp;agrave; veramente utile &amp;egrave; data dalla possibilit&amp;agrave; di definire variabili. Nel nostro file CSS usiamo lo stesso colore in posti diversi. Se volessimo cambiarlo dovremmo modificare tutte le sue occorrenze.&lt;/p&gt; 

&lt;p&gt;SASS rende questo facile permettendoci di definire variabili. Il nome di una variabile deve cominciare con il simbolo dollaro. Definiremo quindi la nostra variabile cos&amp;igrave;:&lt;/p&gt;

&lt;pre class="css"&gt;$main-color: #03507B;&lt;/pre&gt;

&lt;p&gt;Possiamo adesso sostituire tutte le occorrenze del colore con la variabile:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;$main-color: #03507B;

#header {
  background-color: $main-color;
  color: #FFF;
  padding: 4px 100px;
  border-bottom: solid 5px #00395A;

	h1 { 
		font-size: 30px; 
	}
}

a {
  color: $main-color;
  text-decoration: none;

  &amp;amp;:hover { 
   text-decoration: underline;
  }
}&lt;/pre&gt;

&lt;p&gt; Se ricarichiamo la nostra pagina tutto &amp;egrave; rimasto lo stesso. Se adesso volessimo cambiare il colore, basta modificare il valore della variabile per passare da blu a verde.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;$main-color: #1E7B12;&lt;/pre&gt;

&lt;p&gt;Quando ricarichiamo la pagina tutti gli stili che usano quel colore sono adesso cambiati: lo sfondo dell'header, i link ed il bottone &amp;ldquo;New Project&amp;rdquo; sono adesso verdi.Tutto questo &amp;egrave; stato possibile con un singolo cambiamento nel foglio di stile.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/666/original/E268I02.png" width="801" height="381" alt="Abbiamo sostituito il blu con il verde."/&gt;
&lt;/div&gt;

&lt;p&gt;Il bordo in basso all'header &amp;egrave; ancora blu scuro ma vogliamo che abbia una tonalit&amp;agrave; pi&amp;ugrave; scura dell'header stesso. SASS ci permette di definire colori relativi usando delle funzioni. Sul sito di SASS possiamo trovare la &lt;a href="http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html"&gt;completa lista delle funzioni disponibili&lt;/a&gt;, la quale include &lt;a href="http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#darken-instance_method"&gt;una funzione darken&lt;/a&gt; che fa esattamente quello di cui abbiamo bisogno. Passando un colore e una percentuale come parametri otterremo un colore pi&amp;ugrave; scuro come risultato.&lt;/p&gt;

&lt;p&gt;Il colore del bordo in basso &amp;egrave; definito nella dichiarazione per &lt;code&gt;#header&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;#header {
  background-color: $main-color;
  color: #FFF;
  padding: 4px 100px;
  border-bottom: solid 5px #00395A;

	h1 { 
		font-size: 30px; 
	}
}&lt;/pre&gt;

&lt;p&gt;Possiamo sostituirlo con una chiamata a &lt;code&gt;darken&lt;/code&gt; in maniera tale che il bordo abbia lo stesso colore dell'header ma pi&amp;ugrave; scuro del 10%.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;#header {
  background-color: $main-color;
  color: #FFF;
  padding: 4px 100px;
  border-bottom: solid 5px darken($main-color, 10%);

	h1 { 
		font-size: 30px; 
	}
}&lt;/pre&gt;

&lt;p&gt;Ricaricando la pagina il colore del bordo &amp;egrave; adesso un verde scuro.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/667/original/E268I03.png" width="801" height="381" alt="Adesso anche il colore del bordo &amp;egrave; cambiato."/&gt;
&lt;/div&gt;

&lt;h3&gt;Mix-ins&lt;/h3&gt;

&lt;p&gt;Mix-ins sono un'altra feature di SASS che ci aiuta a ridurre la duplicazione. Nel nostro CCS ci sono due elementi che hanno il bordo arrotondato. Poiche' ogni vendor ha delle specifiche diverse, risulta essere pi&amp;ugrave; difficile del previsto ottenere dei bordi arrotondati che funzionino su tutti i browser.&lt;/p&gt;

&lt;pre class="css"&gt;border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
&lt;/pre&gt;

&lt;p&gt;Spostando questo codice in un mix-in, risulter&amp;agrave; molto pi&amp;ugrave; semplice aggiungere la dichiarazione per dei bordi arrotondati. Un mix-in viene definito usando la parola chiave &lt;code&gt;@mixin&lt;/code&gt; e il nome che verr&amp;agrave; poi usato per referenziarlo.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;@mixin rounded-corners {
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}&lt;/pre&gt;

&lt;p&gt;Possiamo adesso applicare il bordo arrotondato ovunque vogliamo chiamando &lt;code&gt;@include&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;.new_project {
  background-color: $main-color;
  color: #FFF;
  padding: 5px 12px;
  margin: 10px 0;
  font-size: 16px;
  @include rounded-corners;
}&lt;/pre&gt;

&lt;p&gt;Per ottenere un &lt;code&gt;border-radius&lt;/code&gt; contenente un valore diverso potremmo definire un altro mix-in. Ma fortunatamente &amp;egrave; anche possibile passare argomenti ai mix-ins in maniera tale da modificare il nostro rounded-corners mix-in nella seguente maniera:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;@mixin rounded-corners($radius) {
  border-radius: $radius;
  -moz-border-radius: $radius;
  -webkit-border-radius: $radius;
}&lt;/pre&gt;

&lt;p&gt;Possiamo adesso passare qualunque valore ogni volta che vogliamo avere un bordo arrotondato.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;.project {
  border: solid 1px #777;
  margin: 20px 0;
  padding: 7px 12px;
  @include rounded-corners(10px);
}&lt;/pre&gt;

&lt;p&gt;Inoltre &amp;egrave; anche possibile specificare un valore di default.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/layout.css.sass&lt;/p&gt;
&lt;pre class="css"&gt;@mixin rounded-corners($radius: 5px) {
  border-radius: $radius;
  -moz-border-radius: $radius;
  -webkit-border-radius: $radius;
}&lt;/pre&gt;

&lt;h3&gt;Utilizzare SASS in file differenti&lt;/h3&gt;

&lt;p&gt;Anche usando SASS i nostri fogli di stile possono diventare lunghi e difficili da mantenere, adesso vedremo come &amp;egrave; possibile organizzare il nostro stile separandolo in file differenti. Abbiamo gi&amp;agrave; un file &lt;code&gt;projects.css.scss&lt;/code&gt; nella nostra applicazione, il quale venne generato al momento della generazione dello scaffold per &lt;code&gt;Projects&lt;/code&gt;. Questo file contiene al momento soltanto un commento, ma possiamo inserire del codice che sar&amp;agrave; compilato e incluso da Rails 3.1 in un singolo file chiamato application.css.&lt;/p&gt;

&lt;p&gt;Vogliamo quindi spostare qualunque codice SASS specifico per project dentro il file &lt;code&gt;projects.css.scss&lt;/code&gt;. Facciamolo e vediamo cosa succede.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/projects.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;.new_project {
  background-color: $main-color;
  color: #FFF;
  padding: 5px 12px;
  margin: 10px 0;
  font-size: 16px;
  @include rounded-corners(5px);
}

.project {
  border: solid 1px #777;
  margin: 20px 0;
  padding: 7px 12px;
  @include rounded-corners(10px);
}

.project h2 { 
  margin: 0; 
}&lt;/pre&gt;

&lt;p&gt;Ricaricando la pagina vedremo che adesso lo stile non &amp;egrave; pi&amp;ugrave; presente.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/668/original/E268I04.png" width="801" height="381" alt="Lo stile non &amp;egrave; pi&amp;ugrave; presente."/&gt;
&lt;/div&gt;

&lt;p&gt;Per controllare se SASS ha lanciato un errore possiamo guardare il file di log o il foglio di stile nel browser.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/669/original/E268I05.png" width="801" height="381" alt="Possiamo vedere l'errore nel foglio di stile."/&gt;
&lt;/div&gt;

&lt;p&gt;Vediamo che un errore di sintassi ha impedito la generazione del foglio di stile. In questo caso l'errore &amp;egrave; dovuto ad una variabile non definita:&lt;/p&gt;

&lt;pre&gt;Undefined variable: &amp;quot;$main-color&amp;quot;.&lt;/pre&gt;

&lt;p&gt;Sembrerebbe che la variabile definita nel file principale non sia stata propagata negli file rimanenti.&lt;/p&gt;

&lt;p&gt;Questo errore &amp;egrave; dovuto al modo in cui Sprockets funziona in Rails 3.1. La variabili non vengono condivise fra i file SASS e possiamo vederne il perch&amp;egrave; nel file &lt;code&gt;application.css&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css&lt;/p&gt;
&lt;pre class="css"&gt;/*
 * This is a manifest file that&amp;#x27;ll automatically include all the stylesheets available in this directory
 * and any sub-directories. You&amp;#x27;re free to add application-wide styles to this file and they&amp;#x27;ll appear at
 * the top of the compiled file, but it&amp;#x27;s generally better to create a new file per style scope.
 *= require_self
 *= require_tree . 
*/&lt;/pre&gt;

&lt;p&gt;La linea &lt;code&gt;require_tree .&lt;/code&gt; dice a Sprockets di includere qualunque file che si trovi dentro la cartella &lt;code&gt;stylesheets&lt;/code&gt;. Il problema &amp;egrave; che ogni file SASS viene compilato separatamente in un singolo CSS e soltanto dopo questi files vengono combinati in uno unico, il che significa che le variabili non vengono condivise tra i files. Per risolvere questo problema dobbiamo rimuovere &lt;code&gt;require_tree .&lt;/code&gt; ed usare SASS per importare ciascun file. Il vantaggio di questo approccio &amp;egrave; che ci permette di definire l'ordine con cui i file vengono caricati. Questo non &amp;egrave; possibile usando &lt;code&gt;require_tree&lt;/code&gt;. Dobbiamo quindi rinominare &lt;code&gt;application.css&lt;/code&gt; in &lt;code&gt;application.css.scss&lt;/code&gt;, rimuovere &lt;code&gt;require_tree&lt;/code&gt; ed importare i nostri stili.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;/*
 * This is a manifest file that&amp;#x27;ll automatically include all the stylesheets available in this directory
 * and any sub-directories. You&amp;#x27;re free to add application-wide styles to this file and they&amp;#x27;ll appear at
 * the top of the compiled file, but it&amp;#x27;s generally better to create a new file per style scope.
 *= require_self
*/
@import &amp;quot;layout.css.scss&amp;quot;;
@import &amp;quot;projects.css.scss&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Questo preserva tutte le nostre variabili, mix-ins e qualunque cosa abbiamo definito. Quando ricarichiamo la pagina il nostro stile funziona ora correttamente e la varibili definite nel foglio di layout sono disponibili per tutti gli altri.&lt;/p&gt;

&lt;h3&gt;SCSS vs SASS&lt;/h3&gt;

&lt;p&gt;Ti potresti chiedere perch&amp;egrave; i file hanno una estensione &lt;code&gt;.scss&lt;/code&gt; se il linguaggio si chiama SASS. Questo &amp;egrave; perch&amp;egrave; SASS supporta due sintassi differenti. SCSS &amp;egrave; la nuova sintassi a partire da SASS 3 ma &lt;a href="http://nex-3.com/posts/102-the-indented-sass-syntax-is-here-to-stay"&gt;quella vecchia &amp;egrave; ancora disponibile&lt;/a&gt; e continuer&amp;agrave; ad essere supportata. Per utilizzarla il file di stile dovr&amp;agrave; avere l'estensione &lt;code&gt;.sass&lt;/code&gt;. La vecchia sintassi &amp;egrave; simile a quella nuova ma non usa parentesi graffe o punti e virgola alla fine di ogni linea, il livello del blocco viene determinato in base al numero di spazi. La sintassi SCSS, essendo in super insieme di CSS, &amp;egrave; pi&amp;ugrave; facile da usare specialmente se bisogna migrare da fogli di stile esistenti.&lt;/p&gt;

&lt;h3&gt;Fogli di stile condizionali&lt;/h3&gt;

&lt;p&gt;Finiamo questo episodio con un piccolo suggerimento. Come possiamo cambiare i file che vengono inclusi in base all'attuale controller? Dato un file &lt;code&gt;projects.css.scss&lt;/code&gt; potremmo che pensare che questo venga incluso solo per le azioni incluse in &lt;code&gt;ProjectsController&lt;/code&gt;, ma non &amp;egrave; cos&amp;igrave;. Tutti i CSS vengono compilati in un singolo file che viene applicato a tutte le pagine dell'applicazione. In genere questo non &amp;egrave; un problema se utilizziamo gli scope correttamente ma certe volte potrebbe non essere abbastanza.&lt;/p&gt; 

&lt;p&gt;Una soluzione &amp;egrave; quella di modificare il tag di apertura del body nel file di layout ed aggiungere un attributo &lt;code&gt;id&lt;/code&gt; avente il nome dell'attuale controller come valore.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;body id=&amp;quot;&amp;lt;%= params[:controller].parameterize %&amp;gt;_controller&amp;quot;&amp;gt;&lt;/pre&gt;

&lt;p&gt;Chiamiamo &lt;code&gt;parameterize&lt;/code&gt; sul nome del controller per rimuovere qualunque carattere speciale. Avendo adesso un unico &lt;code&gt;id&lt;/code&gt; per ciascun controller, possiamo usare questo per introdurre degli scope nei nostri fogli di stile:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/projects.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;#projects_controller
{
  .new_project {
    background-color: $main-color;
    color: #FFF;
    padding: 5px 12px;
    margin: 10px 0;
    font-size: 16px;
    @include rounded-corners(5px);
  }

  .project {
    border: solid 1px #777;
    margin: 20px 0;
    padding: 7px 12px;
    @include rounded-corners(10px);
  }

  .project h2 { 
    margin: 0; 
  }
}&lt;/pre&gt;

&lt;p&gt;Questi stili verranno adesso applicati solo alle azioni del &lt;code&gt;ProjectsController&lt;/code&gt;. Questo significa minori possibilit&amp;agrave; di avere conflitti tra &lt;code&gt;id&lt;/code&gt; o &lt;code&gt;class&lt;/code&gt; in controller diversi.&lt;/p&gt;

&lt;p&gt;Questo &amp;egrave; tutto per questo episodio su SASS. Non abbiamo parlato di tutto quello che SASS pu&amp;ograve; fare, quindi suggeriamo di dare un'occhiata alla documentazione sul &lt;a href="http://sass-lang.com/docs.html"&gt;sito ufficiale&lt;/a&gt; per ottenere maggiori informazioni.&lt;/p&gt;</description>
      <pubDate>Tue, 28 Jun 2011 18:19:53 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/268-concetti-base-n-sass</guid>
      <link>http://it.asciicasts.com/episodes/268-concetti-base-n-sass</link>
    </item>
    <item>
      <title>Concetti base in Coffeescript</title>
      <description>&lt;p&gt;CoffeeScript &amp;egrave; un linguaggio che viene compilato in Javascript. Poich&amp;egrave; &amp;egrave; stato incluso in Rails 3.1 molti sviluppatori gli daranno un occhiata per la prima volta. In questo episodio tradurremo del pre-esistente codice Javascript in Coffeescript, poich&amp;egrave; questo &amp;egrave; un ottimo metodo per impararlo. Il codice in questione &amp;egrave; quello che abbiamo scritto durante l'episodio 261 [&lt;a href="http://railscasts.com/episodes/261-testing-javascript-with-jasmine"&gt;guarda&lt;/a&gt;, &lt;a href="http://asciicasts.com/episodes/261-testing-javascript-with-jasmine"&gt;leggi&lt;/a&gt;] per la validazione dei numeri di carta di credito.&lt;/p&gt;

&lt;p&gt;Se non hai mai usato CoffeeScript il &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;sito ufficiale&lt;/a&gt; &amp;egrave; un ottimo posto da dove cominciare. L&amp;igrave; potrai trovare alcuni esempi di codice CoffeeScript con l'equivalente Javascript che verr&amp;agrave; generato.  Il sito ha anche una pagina nella quale puoi programmare e compilare. Il codice Javascript compilato pu&amp;ograve; essere eseguito nel browser e tutto questo avviene lato client senza nessuna chiamata AJAX al server.&lt;/p&gt;

&lt;p&gt;Il codice che convertiremo &amp;egrave; usato nella pagina sottostante e viene attivato dall'evento &lt;code&gt;blur&lt;/code&gt; appena l'utente finisce di inserire il numero di carta di credito. Il numero inserito viene sottoposto a una validazione modulo 10  ed un messaggio di errore viene visualizzato vicino al campo di input in caso di errore.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/662/original/E267I01.png" width="808" height="375" alt="La pagina per la validazione del numero di carta di credito."/&gt;
&lt;/div&gt;

&lt;p&gt;Il relativo codice Javascript viene mostrato di seguito.&lt;/p&gt;

&lt;pre class="javascript"&gt;var CreditCard = {
  cleanNumber: function(number) {
    return number.replace(/[- ]/g, &amp;quot;&amp;quot;);
  },
  
  validNumber: function(number) {
    var total = 0;
    number = this.cleanNumber(number);
    for (var i=number.length-1; i &amp;gt;= 0; i--) {
      var n = +number[i];
      if ((i+number.length) % 2 == 0) {
        n = n*2 &amp;gt; 9 ? n*2 - 9 : n*2;
      }
      total += n;
    };
    return total % 10 == 0;
  }
};

$(function() {
  $(&amp;quot;#order_credit_card_number&amp;quot;).blur(function() {
    if (CreditCard.validNumber(this.value)) {
      $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;&amp;quot;);
    } else {
      $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;Invalid credit card number.&amp;quot;);
    }
  });
});&lt;/pre&gt;

&lt;p&gt;La versione di Rails in questione &amp;egrave; la 3.1 Release Candidate 1, ed &amp;egrave; stata appena annunciata. Per aggiornare basta eseguire &lt;code&gt;gem install rails --pre&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Primi cambiamenti&lt;/h3&gt;

&lt;p&gt;Per avere un file Coffeescript bisogna aggiungere l'estensione &lt;code&gt;.coffee&lt;/code&gt; al nome del file. Possiamo ancora usare normale file JavaScript in Rails 3.1 mantenendo l'estensione &lt;code&gt;.js&lt;/code&gt;. CoffeeScript &amp;egrave; completamente opzionale.&lt;/p&gt; 

&lt;p&gt;Cominceremo commentando il codice in Javascript in modo tale da implementare a poco a poco la relativa versione in Coffeescript. La prima funzione da tradurre &amp;egrave; &lt;code&gt;cleanNumber&lt;/code&gt; la quale pulisce l'input da eventuali spazi o cancelletti.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/orders.js.coffee&lt;/p&gt;
&lt;pre class="javascript"&gt;var CreditCard = {
  cleanNumber: function(number) {
    return number.replace(/[- ]/g, &amp;quot;&amp;quot;);
  }
}&lt;/pre&gt;

&lt;p&gt;L'equivalenete Coffeescript &amp;egrave; questo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/orders.js.coffee&lt;/p&gt;
&lt;pre class="javascript"&gt;CreditCard =
  cleanNumber: (number) -&amp;gt;
    number.replace /[- ]/g, &amp;quot;&amp;quot;&lt;/pre&gt;

&lt;p&gt;Con Coffeescript possiamo scrivere molto meno codice. Tabs vengono usati per definire il  livello del blocco al posto delle parentesi tradizionali. Questo significa che avremo bisogno di utilizzare gli spazi in maniera consistente.&lt;/p&gt; 

&lt;p&gt;Possiamo anche rimuovere qualunque &lt;code&gt;var&lt;/code&gt; cos&amp;igrave; come non avremo bisogno di usare &lt;code&gt;return&lt;/code&gt; alla fine della funzione. Il valore finale di una funzione viene ritornato automaticamente, esattamente come in Ruby. Anche i punti e virgola non sono necessari e possono essere rimossi.&lt;/p&gt; 

&lt;p&gt;Qualunque chiamata di funzione non ha bisogno nemmeno che i parametri vengano messi fra parentesi. L'eccezione si ha quando la funzione viene chiamata senza parametri, le parentesi sono in questo caso necessarie a Coffeescript per capire che si tratta di una chiamata di funzione.&lt;/p&gt;

&lt;p&gt;Dobbiamo infine cambiare il modo in cui una funzione viene dichiarata. La parola chiave &lt;code&gt;function&lt;/code&gt; deve essere sostituita da &lt;code&gt;-&amp;gt;&lt;/code&gt; dopo gli argomenti della funzione. Un p&amp;ograve; di pratica &amp;egrave; necessaria per abituarsi a questo tipo di dichiarazioni.&lt;/p&gt;

&lt;p&gt;Possiamo adesso compilare il codice e vedere cosa viene generato. Il risultato &amp;egrave; molto simile all'originale.&lt;/p&gt;

&lt;pre class="javascript"&gt;var CreditCard;
CreditCard = {
  cleanNumber: function(number) {
    return number.replace(/[- ]/g, &amp;quot;&amp;quot;);
  }
};&lt;/pre&gt;

&lt;p&gt;Passiamo adesso all funzione &lt;code&gt;validNumber&lt;/code&gt; .&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/orders.js.coffee&lt;/p&gt;
&lt;pre class="javascript"&gt;validNumber: function(number) {
  var total = 0;
  number = this.cleanNumber(number);
  for (var i=number.length-1; i &amp;gt;= 0; i--) {
    var n = +number[i];
    if ((i+number.length) % 2 == 0) {
      n = n*2 &amp;gt; 9 ? n*2 - 9 : n*2;
    }
    total += n;
  };
  return total % 10 == 0;
}&lt;/pre&gt;

&lt;p&gt;Utilizzando lo stesso procedimento di prima otterremo il seguente codice Coffeescript.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/orders.js.coffee&lt;/p&gt;
&lt;pre class="javascript"&gt;validNumber: (number) -&amp;gt;
  total = 0
  number = @cleanNumber(number)
  for i in [(number.length-1)..0]
    n = +number[i]
    if (i+number.length) % 2 == 0
      n = if n*2 &amp;gt; 9 then n*2 - 9 else n*2
    total += n
  total % 10 == 0&lt;/pre&gt;

&lt;p&gt;Abbiamo rimosso tutte le parentesi e i punti e virgola. Anche le parole chiavi &lt;code&gt;var&lt;/code&gt; e &lt;code&gt;return&lt;/code&gt; sono scomparse, ed al posto di &lt;code&gt;function&lt;/code&gt; abbiamo adesso &lt;code&gt;-&amp;gt;&lt;/code&gt;. Ma non &amp;egrave; tutto.&lt;/p&gt; 

&lt;p&gt;Ogni occorrenza della parola chiave &lt;code&gt;this&lt;/code&gt; &amp;egrave; stata sostituita con &lt;code&gt;@&lt;/code&gt; quindi &lt;code&gt;this.cleanNumber&lt;/code&gt; diventa &lt;code&gt;@number&lt;/code&gt;. Possiamo rimuovere le parentesi esterne dal blocco &lt;code&gt;if&lt;/code&gt; poich&amp;egrave; non sono necessarie. Anche l'operatore ternario &amp;egrave; cambiato e possiamo sostituirlo con &lt;code&gt;if then else&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Il resto del codice sembra essere ok; dobbiamo solo cambiare il ciclo &lt;code&gt;for&lt;/code&gt;. CoffeeScript gestice le iterazioni in maniera differente rispetto a JavaScript.Possiamo iterare sugli elementi di un array in questa maniera:&lt;/p&gt;

&lt;pre class="javascript"&gt;for number in [1,2,3]
 alert number&lt;/pre&gt;
 
&lt;p&gt;Il codice Javascript generato &amp;egrave; il seguente:&lt;/p&gt;

&lt;pre class="javascript"&gt;var number, _i, _len, _ref;
_ref = [1, 2, 3];
for (_i = 0, _len = _ref.length; _i &amp;lt; _len; _i++) {
  number = _ref[_i];
  alert(number);
}&lt;/pre&gt;

&lt;p&gt;Potremmo generare lo stesso codice cos&amp;igrave;.&lt;/p&gt;

&lt;pre class="javascript"&gt;alert number for number in [1,2,3]&lt;/pre&gt;

&lt;p&gt;Possiamo sostituire l'array con un range se trattiamo sequenze di numeri.&lt;/p&gt; 
&lt;pre class="javascript"&gt;for number in [1..3]
 alert number&lt;/pre&gt;
 
&lt;p&gt;Questo semplifica il codice generato:&lt;/p&gt;

&lt;pre class="javascript"&gt;var number;
for (number = 1; number &amp;lt;= 3; number++) {
  alert(number);
}&lt;/pre&gt;

&lt;p&gt;Se vogliamo decrementare invece che incrementare basta invertire l'input.&lt;/p&gt;
&lt;pre class="javascript"&gt;for number in [3..1]
 alert number&lt;/pre&gt;
 
&lt;p&gt;Questo &amp;egrave; molto simile a quello che il ciclo &lt;code&gt;for&lt;/code&gt; fa nella nostra funzione.&lt;/p&gt;

&lt;p&gt;Possiamo adesso passare all'ultimo pezzo di codice.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/orders.js.coffee&lt;/p&gt;
&lt;pre class="javascript"&gt;$(function() {
  $(&amp;quot;#order_credit_card_number&amp;quot;).blur(function() {
    if (CreditCard.validNumber(this.value)) {
      $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;&amp;quot;);
    } else {
      $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;Invalid credit &amp;crarr;
        card number.&amp;quot;);
    }
  });
});&lt;/pre&gt;

&lt;p&gt;Questo codice jQuery lega l'esecuzione della validazione all'evento &lt;code&gt;blur&lt;/code&gt;, il quale viene lanciato non appena l'utente finisce di riempire il campo per il numero di carta di credito. Per gestire jQuery in CoffeeScript non abbiamo bisogno di nulla di particolare. L' equivalente codice CoffeeScript &amp;egrave; questo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/orders.js.coffee&lt;/p&gt;
&lt;pre class="javascript"&gt;jQuery -&amp;gt;
  $(&amp;quot;#order_credit_card_number&amp;quot;).blur -&amp;gt;
    if CreditCard.validNumber(@value)
      $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;&amp;quot;)
    else
      $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;Invalid credit &amp;crarr;
        card number.&amp;quot;)&lt;/pre&gt;

&lt;p&gt;Come prima abbiamo rimosso parentesi e punti e virgola, sostituito &lt;code&gt;function&lt;/code&gt; con &lt;code&gt;-&amp;gt;&lt;/code&gt; e referenziato &lt;code&gt;this&lt;/code&gt; con &lt;code&gt;@&lt;/code&gt;. L'ultima cosa da cambiare &amp;egrave; sostituire &lt;code&gt;$&lt;/code&gt; con &lt;code&gt;jQuery&lt;/code&gt;. Questo non ha alcun impatto sulla funzionalit&amp;agrave; ma mette in evidenza il fatto che stiamo usando jQuery.&lt;/p&gt;

&lt;p&gt;&amp;Egrave; giunto il momento di ricaricare il browser e vedere se tutto continua a funzionare come prima.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/663/original/E267I02.png" width="808" height="375" alt="CoffeeScript si comporta alla stessa maniera di Javascript."/&gt;
&lt;/div&gt;

&lt;p&gt;Funziona. Se inseriamo un numero invalido vedremo un messaggio di errore il quale scompare appena inseriamo un valore valido. Se guaridiamo alla fine del file risultante troveremo il codice Javascript generato.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;http://localhost:3000/assets/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;(function() {
  var CreditCard;
  CreditCard = {
    cleanNumber: function(number) {
      return number.replace(/[- ]/g, &amp;quot;&amp;quot;);
    },
    validNumber: function(number) {
      var i, n, total, _ref;
      total = 0;
      number = this.cleanNumber(number);
      for (i = _ref = number.length - 1; _ref &amp;lt;= 0 ? i &amp;lt;= 0 : &amp;crarr;
        i &amp;gt;= 0; _ref &amp;lt;= 0 ? i++ : i--) {
        n = +number[i];
        if ((i + number.length) % 2 === 0) {
          n = n * 2 &amp;gt; 9 ? n * 2 - 9 : n * 2;
        }
        total += n;
      }
      return total % 10 === 0;
    }
  };
  jQuery(function() {
    return $(&amp;quot;#order_credit_card_number&amp;quot;).blur(function() {
      if (CreditCard.validNumber(this.value)) {
        return $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;&amp;quot;);
      } else {
        return $(&amp;quot;#credit_card_number_error&amp;quot;).text(&amp;quot;Invalid &amp;crarr; 
          credit card number.&amp;quot;);
      }
    });
  });
}).call(this);&lt;/pre&gt;

&lt;h3&gt;Debuggare&lt;/h3&gt;

&lt;p&gt;Ma cosa succede se abbiamo un errore di sintassi in CoffeeScript? Se cambiamo il nostro CoffeeScript in maniera tale che non compili correttamente non riceveremo alcun messaggio dal browser. Ma se invece diamo un'occhiata alla console troveremo l'errore.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/664/original/E267I03.png" width="814" height="594" alt="L'errore viene visualizzato nella console di sviluppo."/&gt;
&lt;/div&gt;

&lt;p&gt;Ci sono abbastanza informazioni per capire quale sia l'errore e quale linea abbia causato.&lt;/p&gt; 

&lt;p&gt;Questo &amp;egrave; tutto per questo episodio su CoffeeScript, ci sono molte altre cose da imparare a proposito di questo divertente linguaggio, quindi consigliamo di dare un'occhiata al sito ufficiale.&lt;/p&gt;</description>
      <pubDate>Sun, 03 Jul 2011 18:42:12 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/267-concetti-base-in-coffeescript</guid>
      <link>http://it.asciicasts.com/episodes/267-concetti-base-in-coffeescript</link>
    </item>
    <item>
      <title>OmniAuth - Parte 1</title>
      <description>&lt;p&gt;Circa due settimane fa, nell&amp;rsquo;episodio 233 [&lt;a href="http://railscasts.com/episodes/233-engage-with-devise"&gt;guarda&lt;/a&gt;, &lt;a href="http://railscasts.com/episodes/233-engage-with-devise"&gt;leggi&lt;/a&gt;] ho presentato un servizio chiamto Janrain Engage, un modo centralizzato per gestire l&amp;rsquo;autenticazione tramite servizi Twitter, OpenID and Facebook. E&amp;rsquo; un servizio fantastico ma &amp;egrave; come se ci fosse qualcuno tra la tua applicazione e il provider di autenticazione e questo &amp;egrave; un aspetto negativo. Una soluzione migliore potrebbe essere una gemma o un plugin che ti permetterebbe di usare nella nostra applicazione l&amp;rsquo;autenticazione fornita da terze parti senza utilizzare servizi esterni.&lt;/p&gt;
    
&lt;p&gt;OnmiAuth &amp;egrave; una gemma nuova che fornisce un&amp;rsquo;unica soluzione per connettersi a diversi servizi. Se il servizio che vuoi usare per autenticarti non &amp;egrave; supportato da OmniAuthm, aggiungere un proprio provider &amp;egrave; davvero semplice. OmniAuth &amp;egrave; una una collezione di Rack middleware che da molta flessibilit&amp;agrave; su come usarla.&lt;/p&gt;

&lt;p&gt;C&amp;rsquo;&amp;egrave; un bel articolo nel blog di &lt;a href="http://blog.railsrumble.com/blog/2010/10/08/intridea-omniauth"&gt;Rails Rumble blog&lt;/a&gt; che spiega in dettaglio come aggiungere OmniAuth ad una applicazione Rails. L&amp;rsquo;articolo mostra come creare un sistema di autenticazione da zero, ma qui spiegheremo come integrare OmniAuth in una applicazione che possiede gi&amp;agrave; un sistema di autenticazione. Qui useremo Devise, si potr&amp;agrave; adattare ad Authlogic o ad altri sistemi di autenticazione specifici facilmente.&lt;/p&gt;
    
&lt;h3&gt;Aggiungere OmniAuth alla nostra applicazione&lt;/h3&gt;

&lt;p&gt;Prenderemo come esempio l&amp;rsquo;episodio 209, una semplice todo-list, che usa Devise per gestire l&amp;rsquo;autenticazione degli utenti. I link &amp;ldquo;Sign up &amp;rdquo; &amp;ldquo;Sign in &amp;rdquo; portano l&amp;rsquo;utente ad una pagina dove si pu&amp;ograve; accedere o registrarsi fornendo un nome utente e password. Inizieremo entrando con on un account gi&amp;agrave; esistente in modo da renderci pi&amp;ugrave; semplice lo sviluppo di autenticazione tramite provider.&lt;/p&gt;
    
&lt;div class="imageWrapper"&gt;
      &lt;img src="/system/photos/487/original/E235I01.png" width="800" height="426" alt=""/&gt;
&lt;/div&gt;
    
&lt;p&gt;OmniAuth si presenta come una gemma ed &amp;egrave; facile includerlo nella nostra applicazione modificamndo il &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFileWrapper"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;
source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.0&amp;#x27;

gem &amp;#x27;sqlite3-ruby&amp;#x27;, :require =&amp;gt; &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;devise&amp;#x27;, &amp;#x27;1.1.3&amp;#x27;

gem &amp;#x27;omniauth&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;Eseguiamo il &lt;code&gt;bundle install&lt;/code&gt; (o solo &lt;code&gt;bundle&lt;/code&gt;) per istallare le gemme e tutte le sue dipendenze. OmniAuth ha diverse dipendenze ma sar&amp;agrave; il budler che si occuper&amp;agrave; di installarle tutte.&lt;/p&gt;

&lt;p&gt;Il prossimo passo &amp;egrave; quello di andare nella directory dell&amp;rsquo;applicazione &lt;code&gt;/config/initializers&lt;/code&gt; e creare un nuovo file. Lo chiameremo &lt;code&gt;omniauth.rb&lt;/code&gt; ma il nome non &amp;egrave; importante. In questo file aggiungiamo &lt;code&gt;OmniAuth::Builder&lt;/code&gt; al middleware della nostra applicazione e definiamo i provider che vogliamo utilizzare.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/omniauth.rb&lt;/p&gt;

&lt;pre class="ruby"&gt;
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, &amp;#x27;CONSUMER_KEY&amp;#x27;, &amp;#x27;CONSUMER_SECRET&amp;#x27;
  provider :facebook, &amp;#x27;APP_ID&amp;#x27;, &amp;#x27;APP_SECRET&amp;#x27;
  provider :linked_in, &amp;#x27;CONSUMER_KEY&amp;#x27;, &amp;#x27;CONSUMER_SECRET&amp;#x27;
end
&lt;/pre&gt;

&lt;p&gt;In questa applicazione noi andremo ad usare solo Twitter, anche se ci sono molti provider che si potrebbero scegliere, quindi rimuoviamo le ultime due linee. Per supportare l&amp;rsquo;autenticazione attraverso Twitter abbiamo la necessit&amp;agrave; di fare il setup della nostra applicazione andando alla &lt;a href="http://dev.twitter.com/"&gt;sezione per gli sviluppatori&lt;/a&gt; per registrarci. Il form di registrazione &amp;egrave; facile da compilare ed una volta registrata la nostra applicazione, avremo la chiave e un charset segreto che dovremo copiare nel nostro file initializer.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/omniauth.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, &amp;#x27;s3dXXXXXXXXXXXX&amp;#x27;, &amp;#x27;lR23XXXXXXXXXXXXXXXXXXXX&amp;#x27;
end
&lt;/pre&gt;

&lt;p&gt;Se avviamo il server dell&amp;rsquo;applicazione gi&amp;agrave; possiamo vedere OmniAuth in azione . Se visitiamo l&amp;rsquo;url &lt;code&gt;/auth/twitter&lt;/code&gt; saremo rediretti a Twitter e ci verr&amp;agrave; chiesto se vogliamo permettere l&amp;rsquo;accesso a questa applicazione&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
      &lt;img src="/system/photos/488/original/E235I02.png" width="802" height="468" alt="" /&gt;
&lt;/div&gt;
    
&lt;p&gt;Se clicchiamo su &amp;ldquo;Allow &amp;rdquo; saremo rediretti alla nostra applicazione con l&amp;rsquo;URL &lt;code&gt;/auth/twitter/callback&lt;/code&gt;. La nostra applicazione ha bisogno di gestire questa URL che riguarda ci&amp;ograve; che succede dopo che un utente ha effettuato l&amp;rsquo;accesso, il modo in cui gestiamo questa risposta dipende sa noi e questo rende OmniAuth molto flessibile. In questo caso creeremo una risorsa separata che la chiameremo &lt;code&gt;Authentication&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Potremmo creare il model a il controller sepratamente, ma per rendere le cose pi&amp;ugrave; semplici useremo il Nifty Scaffold generator di Ryan Bates per creare il model, la view e il controller con un solo comando. La risorsa &lt;code&gt;Authentication&lt;/code&gt; avr&amp;agrave; un campo &lt;code&gt;user_id&lt;/code&gt;, un campo &lt;code&gt;provider&lt;/code&gt; che sar&amp;agrave; valorizzato con il nome del provider, e .g. &amp;ldquo; Twitter &amp;rdquo; o &amp;ldquo;Facebook &amp;rdquo; e un campo &lt;code&gt;uid&lt;/code&gt; nel quale verr&amp;agrave; memorizzato l&amp;rsquo;identificativo utente del provider. Per il controller ci serviranno le action &lt;code&gt;index&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt; e &lt;code&gt;destroy&lt;/code&gt;&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rails g nifty:scaffold authentication user_id:integer
provider:string uid:string index create destroy
&lt;/pre&gt;

&lt;p&gt;Dopo che si esegue questo comando, facciamo partire il migrate del database.&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rake db:migrate
&lt;/pre&gt;

&lt;p&gt;Successivamente settiamo le relazione tra i modelli &lt;code&gt;User&lt;/code&gt; e &lt;code&gt;Authentication&lt;/code&gt; . Un utente potr&amp;agrave; autenticarsi in un un numero di modi differenti cos&amp;igrave; da avere pi&amp;ugrave; autenticazioni.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class User &amp;lt; ActiveRecord::Base
  has_many :authentications
  # Include default devise modules. Others available are:
  # :token_authenticatable, :lockable, :timeoutable and :activatable
  # :confirmable,
  devise :database_authenticatable, :registerable, 
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation
end
&lt;/pre&gt;

&lt;p&gt;Allo stesso modo &lt;code&gt;Authentication&lt;/code&gt; &amp;#x27;belong to&amp;#x27; &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/authentication.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class Authentication &amp;lt; ActiveRecord::Base
  belongs_to :user
end
&lt;/pre&gt;

&lt;p&gt;Lo scaffold ha pure generato un &lt;code&gt;AuthenticationsController&lt;/code&gt; che possiamo usare per gestire le risposte di OmniAuth. Mapperemo l&amp;rsquo;URL di risposta alla action &lt;code&gt;create&lt;/code&gt;, modificando il file di routes&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
ProjectManage::Application.routes.draw do |map|
  match &amp;#x27;/auth/:provider/callback&amp;#x27; =&amp;gt; &amp;#x27;authentications#create&amp;#x27;
  devise_for :users
  resources :projects
  resources :tasks
  resources :authentications
  root :to =&amp;gt; &amp;#x27;projects#index&amp;#x27;
end
&lt;/pre&gt;

&lt;p&gt;Da notare la colonna della stringa che viene matchata . Questo significa che noi possiamo fare il matching di ogni provider come parametro.&lt;/p&gt;

&lt;p&gt;Dentro la action &lt;code&gt;create&lt;/code&gt; possiamo fare il fetch dei dettagli di autenticazione con una chiamata a&lt;code&gt;request.env[&amp;quot;rack.auth&amp;quot;]&lt;/code&gt;. (Nelle versioni di OmniAuth successive sar&amp;agrave; &lt;code&gt;request.env[&amp;quot;omniauth.auth&amp;quot;]&lt;/code&gt;). Per ora ci limiteremo fare il render del testo in modo da vedere quali sono le informazioni contenute.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/authentication_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class AuthenticationsController &amp;lt; ApplicationController
  def index
  end
  
  def create
    render :text =&amp;gt; request.env[&amp;quot;rack.auth&amp;quot;].to_yaml
  end
  
  def destroy
  end
end
&lt;/pre&gt;

&lt;p&gt;Se visitiamo &lt;code&gt;/auth/twitter&lt;/code&gt; adesso e ci autentichiamo su Twitter avremo come risposta molte informazioni.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
      &lt;img src="/system/photos/489/original/E235I03.png" width="798" height="558" alt=""/&gt;
&lt;/div&gt;

&lt;p&gt;Le Informazioni restituite sono un hash di hash. All&amp;rsquo;inizio della lista c&amp;rsquo;&amp;egrave; il &lt;code&gt;provider&lt;/code&gt; e il campo &lt;code&gt;uid&lt;/code&gt; che ci interessano. Conserveremo sia il nome del provider che che l&amp;rsquo;uid nel nostro modello di &lt;code&gt;Authentication&lt;/code&gt;. Alla fine del file c&amp;rsquo;&amp;egrave; qualche informazione sull&amp;rsquo;utente che potrebbe essere utile salvare in &lt;code&gt;User&lt;/code&gt; model.&lt;/p&gt;

&lt;pre class="terminal"&gt;
user_info: 
  nickname: eifion
  name: Eifion
  location: North Wales
  image: http://a1.twimg.com/profile_images/434158309/Adium_Icon_normal.png
  description: Web developer using .Net and Windows by day and Ruby and Rails on OS X the rest of the time. I run http://asciicasts.com
  urls: 
    Website: http://asciicasts.com
&lt;/pre&gt;

&lt;h3&gt;Salvare le Informazioni di Authentication&lt;/h3&gt;
&lt;p&gt;Abbiamo bisogno di modificare la action &lt;code&gt;create&lt;/code&gt; e cambiare il suo comportamento a seconda dello stato corrente dell&amp;rsquo;utente, ma prima vedremo l&amp;rsquo;esempio pi&amp;ugrave; facile. Quando un utente &amp;egrave; attualmente connesso vogliamo solo aggiungere questa nuova autenticazione ai loro account utente.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/authentications_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def create
  auth = request.env[&amp;quot;rack.auth&amp;quot;] current_user.authentications.create(:provider =&amp;gt; auth [&amp;#x27;provider&amp;#x27;], :uid =&amp;gt; auth[&amp;#x27;uid&amp;#x27;])
  flash[:notice] = &amp;quot;Authentication successful.&amp;quot;
  redirect_to authentications_url
end
&lt;/pre&gt;

&lt;p&gt;Nella action &lt;code&gt;create&lt;/code&gt; possiamo ottenere informazioni per l&amp;rsquo;autenticazione in un hash e creare una nuova &lt;code&gt;Authentication&lt;/code&gt; per l&amp;rsquo;utente basata su due parametri grazie alle informazioni ritornate dal provider di autenticazione. Quindi creiamo un messaggio &lt;code&gt;flash&lt;/code&gt; e ritorneremo nella action &lt;code&gt;index&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se visitiamo &lt;code&gt;/auth/twitter&lt;/code&gt; and ci autentichiamo, saremo rediretti nella pagina index dove potremo vedere i dettagli della nuova autenticazione appena effettuata con il provider e l&amp;rsquo;uid corretto.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/490/original/E235I04.png" width="801" height="292" alt="" /&gt;
&lt;/div&gt;
    
&lt;h3&gt;Migliorare il Look della pagina Index&lt;/h3&gt;

&lt;p&gt;C&amp;rsquo;&amp;egrave; un account molto utile su GitHub chiamato &lt;a href="http://github.com/intridea/authbuttons"&gt;Authbuttons&lt;/a&gt;, che ha le icone per molti provider differenti. Possiamo usarli per migliorare il look della pagina dove si sceglie il provider di autenticazione. Per convenienza andremo a gestire tutto dentro la action &lt;code&gt;index&lt;/code&gt; di &lt;code&gt;AuthenticationsController&lt;/code&gt; ma in produzione si potrebbe spostare in una pagina separata.&lt;/p&gt;

&lt;p&gt;Prima di fare questo abbiamo bisogni di cambiare il codice nella &lt;code&gt;index&lt;/code&gt;. Il codice dello scaffolding generato far&amp;agrave; la fetch di tutte le autenticazioni. Cambiamolo in modo che venga selezionato solo l&amp;rsquo;autenticazione del current_user.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/authentications_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def index
  @authentications = current_user.authentications if current_user
end
&lt;/pre&gt;

&lt;p&gt;Allo stesso modo possiamo cambiare la action &lt;code&gt;destroy&lt;/code&gt; cos&amp;igrave; che non si possono eliminare autenticazione che non &lt;code&gt;belong_to&lt;/code&gt; al current user.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/authentications_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def destroy
  @authentication = current_user.authentications.find(params[:id])
  @authentication.destroy
  flash[:notice] = &amp;quot;Successfully destroyed authentication.&amp;quot;
  redirect_to authentications_url
end
&lt;/pre&gt;

&lt;p&gt;Successivamente abbiamo bisogno di cambiare il codice della view, nulla di complicato solo qualche modifica.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/authentications/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;% title &amp;quot;Sign In&amp;quot; %&amp;gt;
&amp;lt;% if @authentications %&amp;gt;
 &amp;lt;% unless @authentications.empty? %&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;You can sign in to this account using:&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
   &amp;lt;div class=&amp;quot;authentications&amp;quot;&amp;gt;
    &amp;lt;% for authentication in @authentications %&amp;gt;
     &amp;lt;div class=&amp;quot;authentication&amp;quot;&amp;gt;
      &amp;lt;%= image_tag &amp;quot;#{authentication.provider}_32.png&amp;quot;, :size =&amp;gt; &amp;quot;32x32&amp;quot; %&amp;gt;
      &amp;lt;div class=&amp;quot;provider&amp;quot;&amp;gt;&amp;lt;%= authentication.provider.titleize%&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&amp;quot;uid&amp;quot;&amp;gt;&amp;lt;%= authentication.uid %&amp;gt;&amp;lt;/div&amp;gt;
       &amp;lt;%= link_to &amp;quot;X&amp;quot;, authentication, :confirm =&amp;gt; &amp;#x27;Are you sure you want to remove this authentication option?&amp;#x27;, :method =&amp;gt; :delete, :class =&amp;gt; &amp;quot;remove&amp;quot; %&amp;gt;
     &amp;lt;/div&amp;gt;
     &amp;lt;% end %&amp;gt;
     &amp;lt;div class=&amp;quot;clear&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
   &amp;lt;% end %&amp;gt;
   &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Add another service to sign in with:&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;% else %&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Sign in through one of these services:&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;

&amp;lt;a href=&amp;quot;/auth/twitter&amp;quot; class=&amp;quot;auth_provider&amp;quot;&amp;gt;
  &amp;lt;%= image_tag &amp;quot;twitter_64.png&amp;quot;, :size =&amp;gt; &amp;quot;64x64&amp;quot;, :alt =&amp;gt; &amp;quot;Twitter&amp;quot; %&amp;gt;Twitter&amp;lt;/a&amp;gt;
&amp;lt;a href=&amp;quot;/auth/facebook&amp;quot; class=&amp;quot;auth_provider&amp;quot;&amp;gt;
  &amp;lt;%= image_tag &amp;quot;facebook_64.png&amp;quot;, :size =&amp;gt; &amp;quot;64x64&amp;quot;, :alt =&amp;gt; &amp;quot;Facebook&amp;quot; %&amp;gt;Facebook&amp;lt;/a&amp;gt;
&amp;lt;a href=&amp;quot;/auth/google_apps&amp;quot; class=&amp;quot;auth_provider&amp;quot;&amp;gt;
  &amp;lt;%= image_tag &amp;quot;google_64.png&amp;quot;, :size =&amp;gt; &amp;quot;64x64&amp;quot;, :alt =&amp;gt; &amp;quot;Google&amp;quot; %&amp;gt;Google&amp;lt;/a&amp;gt;
&amp;lt;a href=&amp;quot;/auth/open_id&amp;quot; class=&amp;quot;auth_provider&amp;quot;&amp;gt;
  &amp;lt;%= image_tag &amp;quot;openid_64.png&amp;quot;, :size =&amp;gt; &amp;quot;64x64&amp;quot;, :alt =&amp;gt; &amp;quot;OpenID&amp;quot; %&amp;gt;OpenID&amp;lt;/a&amp;gt;
&amp;lt;div class=&amp;quot;clear&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Se ricarichiamo la pagina di autenticazione possiamo vedere come sia migliorata nel look.&lt;/p&gt;
&lt;div class="imageWrapper"&gt;
      &lt;img src="/system/photos/491/original/E235I05.png" width="804" height="433" alt="" /&gt;
&lt;/div&gt;

&lt;p&gt;La nostra applicazione non supporta tutti i servizi mostrati negli screenshoot, ma quelli che si potrebbero supportare. Anche se questa pagina &amp;egrave; migliorata nel look, ha un bug. Autenticandosi con Twitter proviamo a fare una seconda autenticazione sempre con Twitter, verr&amp;agrave; creato un nuovo record gi&amp;agrave; esistente in Authentication.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/492/original/E235I06.png" width="802" height="483" alt="" /&gt;
&lt;/div&gt;

&lt;p&gt;Il problema &amp;egrave; abbastanza facile da risolvere, basta modificare la &lt;code&gt;create&lt;/code&gt; action di &lt;code&gt;AuthenticationController&lt;/code&gt; cos&amp;igrave; da usare &lt;code&gt;find_or_create_by_&lt;/code&gt; per vedere se l&amp;#x27;utente si &amp;egrave; autenticato con quel provider prima di crearne uno nuovo record in Authentication.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/authentication_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def create
  auth = request.env[&amp;quot;rack.auth&amp;quot;]
  current_user.authentications.find_or_create_by_provder_and_uid(auth[&amp;#x27;provider&amp;#x27;], auth[&amp;#x27;uid&amp;#x27;])
  flash[:notice] = &amp;quot;Authentication successful.&amp;quot;
  redirect_to authentications_url
end
&lt;/pre&gt;

&lt;p&gt;Adesso se vogliamo rimuovere la seconda autenticazione e riprovare ad autenticarci sempre via Twitter avremo solo una autenticazione per utente&lt;/p&gt;

&lt;p&gt;Una delle cosa che non abbiamo affrontato &amp;egrave; l&amp;rsquo;autenticazione tramite provider per utenti non registrati. Se andiamo a guardare nella action create vedremo che il codice presuppone che noi abbiamo un current_user. cosa succede quando si prova ad autenticarsi via Twitter senza essere gi&amp;agrave; registrati al sito? Parleremo di questo problema nel prossimo episodio.&lt;/p&gt;</description>
      <pubDate>Sun, 03 Jul 2011 18:35:39 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/235-omniauth-parte-1</guid>
      <link>http://it.asciicasts.com/episodes/235-omniauth-parte-1</link>
    </item>
    <item>
      <title>Simple Form</title>
      <description>&lt;p&gt;Pochi mesi fa abbiamo trattato in un paio di episodi il gem Formtastic [&lt;a href="http://railscasts.com/episodes/184-formtastic-part-1"&gt;guarda&lt;/a&gt;, &lt;a href="http://it.asciicasts.com/episodes/184-formtastic-parte-1"&gt;leggi&lt;/a&gt;]. Questo plugin offre la possibilit&amp;agrave; di generare rapidamente il codice delle viste per le form in Rails. In questo episodio daremo un&amp;rsquo;occhiata ad un gem alternativo, chiamato &lt;a href="http://github.com/plataformatec/simple_form"&gt;SimpleForm&lt;/a&gt;. Come Formtastic, SimpleForm fornisce un modo pi&amp;ugrave; semplice per generare il codice delle viste rispetto allo standard Rails. Se conoscete gi&amp;agrave; Formtastic, le chiamate ai metodi SimpleForm vi sembreranno familiari, dal momento che in effetti lo sono.&lt;/p&gt; 

&lt;p&gt;La domanda da un milione di dollari &amp;egrave;, viste tutte queste analogie fra i due gem, perch&amp;egrave; preferire SimpleForm a Formtastic? Una delle ragioni &amp;egrave; che SimpleForm &amp;egrave; pi&amp;ugrave; leggero. Non include un foglio di stile che si aspetta essere usato, ma si concentra esclusivamente sulla generazione  del markup HTML. E&amp;rsquo; anche pi&amp;ugrave; personalizzabile ed estendibile di Formtastic. Se avete usato Formtastic e vi &amp;egrave; sembrato che vi condizionasse un po&amp;rsquo; troppo a fare a modo suo e che vi forzasse ad usare del markup che non avreste voluto, allora vale la pena che esploriate anche SimpleForm.&lt;/p&gt;

&lt;h3&gt;Integrare SimpleForm in un&amp;rsquo;applicazione&lt;/h3&gt;

&lt;p&gt;Per dimostrare SimpleForm, aggiornaremo una form gi&amp;agrave; scritta usando codice di vista standard di Rails. L&amp;rsquo;applicazione &amp;egrave; una semplice applicazione di e-commerce con una serie di prodotti, ciascuno dei quali appartiene ad una categoria e la form che abbiamo intenzione di modificare &amp;egrave; quella di creazione di un nuovo prodotto. Questa form ha una serie di diversi tipi di campo, per cui funger&amp;agrave; molto bene da esempio per convertire all&amp;rsquo;uso di SimpleForm.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/481/original/E234I01.png" width="800" height="570" alt="La form attuale di creazione di un nuovo prodotto."/&gt;
&lt;/div&gt;

&lt;p&gt;Per usare SimpleForm dobbiamo per prima cosa aggiungere il gem al &lt;code&gt;Gemfile&lt;/code&gt; dell&amp;rsquo;applicazione:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;
gem &amp;quot;simple_form&amp;quot;
&lt;/pre&gt;

&lt;p&gt;Poi, per assicurarci che venga installato tutto, dobbiamo lanciare:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ bundle install
&lt;/pre&gt;

&lt;p&gt;Ora che il gem &amp;egrave; installato, dobbiamo lanciare un generatore che aggiunga all&amp;rsquo;applicazione un paio di file di cui ha bisogno SimpleForm:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rails g simple_form:install
    &lt;span class="passed"&gt;create&lt;/span&gt;  config/initializers/simple_form.rb
    &lt;span class="passed"&gt;create&lt;/span&gt;  config/locales/simple_form.en.yml
    &lt;span class="passed"&gt;create&lt;/span&gt;  lib/templates/erb/scaffold/_form.html.erb
&lt;/pre&gt;

&lt;p&gt;Questi file generati sono usati principalmente per la personalizzazione delle form e li esamineremo in dettaglio fra poco. Prima, per&amp;ograve;, aggiorneremo la form dei prodotti che attualmente appare cos&amp;igrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/view/products/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= form_for @product do |f| %&amp;gt;
  &amp;lt;%= f.error_messages %&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :name %&amp;gt;
    &amp;lt;%= f.text_field :name %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :price %&amp;gt;
    &amp;lt;%= f.text_field :price %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :released_on %&amp;gt;
    &amp;lt;%= f.date_select :released_on %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :category_id %&amp;gt;
    &amp;lt;%= f.collection_select :category_id, Category.all, :id, :name %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :rating %&amp;gt;
    &amp;lt;%= f.select :rating, 1..5 %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :discontinued %&amp;gt;
    &amp;lt;%= f.check_box :discontinued %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= f.submit %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Le due principali modifiche che dobbiamo fare alla form sono di sostituire &lt;code&gt;form_for&lt;/code&gt; con &lt;code&gt;simple_form_for&lt;/code&gt; e tutte le coppie label ed input con un unico metodo di SimpleForm:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/view/products/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= simple_form_for @product do |f| %&amp;gt;
  &amp;lt;%= f.error_messages %&amp;gt;
  &amp;lt;%= f.input :name %&amp;gt;
  &amp;lt;%= f.input :price %&amp;gt;
  &amp;lt;%= f.input :released_on %&amp;gt;
  &amp;lt;%= f.association :category %&amp;gt;
  &amp;lt;%= f.input :rating %&amp;gt;
  &amp;lt;%= f.input :discontinued %&amp;gt;
  &amp;lt;%= f.button :submit %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Per la maggior parte dei control della form possiamo usare il metodo &lt;code&gt;f.input&lt;/code&gt;. Uno dei campi per il quale dobbiamo utilizzare qualcosa di diverso &amp;egrave; il &lt;code&gt;category&lt;/code&gt;. Nella form originale questo campo usava &lt;code&gt;collection_select&lt;/code&gt; per renderizzare una tendina contenente tutte le categorie.&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/app/view/products/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= f.collection_select :category_id, Category.all, :id, :name %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Con SimpleForm possiamo sostituire tutto ci&amp;ograve; con &lt;code&gt;f.association&lt;/code&gt; che fa la stessa cosa.&lt;/p&gt;
&lt;p&gt;Possiamo ora ricaricare la form e vedere come viene mostrata da SimpleForm:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/482/original/E234I02.png" width="800" height="490" alt="La form renderizzata da SimpleForm."/&gt;
&lt;/div&gt;

&lt;p&gt;La form appare piuttosto diversa ora rispetto a prima, perch&amp;egrave; non ha pi&amp;ugrave; lo stile che aveva in precedenza, ma &amp;egrave; semplice rimediare adattando i nostri fogli di stile ai nomi delle classi usate da SimpleForm nelle sue form:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/stylesheets/application.css&lt;/p&gt;
&lt;pre class="css"&gt;
.simple_form label {
  float: left;
  width: 100px;
  text-align: right;
  margin: 2px 10px;
}

.simple_form div.input {
  margin-bottom: 10px;
}

.simple_form div.boolean, .simple_form input[type=&amp;#x27;submit&amp;#x27;] {
  margin-left: 120px;
}

.simple_form div.boolean label {
  float: none;
  margin: 0;
}
&lt;/pre&gt;

&lt;p&gt;Quando usate SimpleForm nelle vostre applicazioni, dovrete personalizzare questi stili per adattarli all&amp;rsquo;aspetto della vostra applicazione, ma il CSS riportato qui sopra vi d&amp;agrave; gi&amp;agrave; un&amp;rsquo;idea circa i nomi delle classi usati dagli elementi HTML generati da SimpleForm. Sistemati gli stili, la nostra form ora appare migliore:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/483/original/E234I03.png" width="800" height="469" alt="La form con i CSS a posto."/&gt;
&lt;/div&gt;

&lt;h3&gt;Campi personalizzati&lt;/h3&gt;

&lt;p&gt;Per i campi per i quali abbiamo usato &lt;code&gt;f.input&lt;/code&gt;, SimpleForm ha automaticamente capito il tipo della colonna e per questo vediamo che &amp;ldquo;Released on&amp;rdquo; &amp;egrave; stato renderizzato come una colonna di tipo data mentre invece &amp;ldquo;Discontinued&amp;rdquo; come checkbox, dal momento che rappresenta una colonna booleana. In quanto associazione, il campo &amp;ldquo;Category&amp;rdquo; &amp;egrave; stato renderizzato come tendina con l&amp;rsquo;opzione vuota. Se volessimo personalizzare questi campi, facendoli apparire in modo diverso, dovremmo aggiungere alcune option. Per esempio, possiamo rimuovere l&amp;rsquo;opzione vuota dalla tendina &amp;ldquo;Category&amp;rdquo;, aggiungendo l&amp;rsquo;opzione &lt;code&gt;:include_blank&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/view/products/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= f.association :category, :include_blank =&amp;gt; false %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;La form originale aveva una tendina per il campo rating, ma ora ci troviamo un campo di testo. Possiamo ripristinare la tendina, usando l&amp;rsquo;opzione &lt;code&gt;:collection&lt;/code&gt; e passando ad essa un intervallo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/view/products/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= f.input :rating, :collection =&amp;gt; 1..5 %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Se invece volessimo visualizzare la lista come radio button, potremmo usare l&amp;rsquo;opzione &lt;code&gt;:as&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/view/products/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= f.input :rating, :collection =&amp;gt; 1..5, :as =&amp;gt; :radio %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Al ricaricamento della form, ora vedremo che l&amp;rsquo;opzione vuota &amp;egrave; scomparsa dalla tendina e che il campo rating &amp;egrave; mostrato come radio button.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/484/original/E234I04.png" width="800" height="423" alt="Il campo rating &amp;egrave; ora mostrato come serie di radio button."/&gt;
&lt;/div&gt;

&lt;p&gt;Un&amp;rsquo;altra bella funzionalit&amp;agrave; di SimpleForm &amp;egrave; il riconoscimento automatico dei campi obbligatori. Possiamo illustrarvi la cosa, rendendo obbligatori i campi &lt;code&gt;name&lt;/code&gt; e &lt;code&gt;price&lt;/code&gt; nel modello &lt;code&gt;Product&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/product.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class Product &amp;lt; ActiveRecord::Base
  attr_accessible :name, :price, :released_on, :category_id, 
  :rating, :discontinued
  belongs_to :category  
  validates_presence_of :name, :price
end
&lt;/pre&gt;

&lt;p&gt;E&amp;rsquo; tutto ci&amp;ograve; che dobbiamo fare. Al ricaricamento della form vedremo questi due campi contrassegnati da un asterisco e se provassimo a fare il submit della form senza averli compilati, vedremmo i messaggi di errore relativi:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/485/original/E234I05.png" width="800" height="586" alt="La form che mostra gli errori per i campi obbligatori."/&gt;
&lt;/div&gt;

&lt;p&gt;Possiamo anche facilmente aggiungere un messaggio di suggerimento per ogni campo. Poniamo di voler dare un suggerimento che indichi che i prezzi si intendono in sterline. Dobbiamo solo aggiungere un&amp;rsquo;opzione &lt;code&gt;:hint&lt;/code&gt; al campo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/apps/views/products/_form.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= f.input :price, :hint =&amp;gt; &amp;quot;prices should be in UKP.&amp;quot; %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Ci&amp;ograve; aggiunger&amp;agrave; un suggerimento subito dopo il campo della form:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/486/original/E234I06.png" width="800" height="442" alt="Il campo Price ora ha un suggerimento."/&gt;
&lt;/div&gt;

&lt;p&gt;Ci sono ulteriori informazioni su tutte queste opzioni di campo nella &lt;a href="http://github.com/plataformatec/simple_form#readme"&gt;documentazione di README&lt;/a&gt; di SimpleForm. Vale la pena dare un&amp;rsquo;occhiata anche alla &lt;a href="http://github.com/justinfrench/formtastic#readme"&gt;documentazione di Formtastic&lt;/a&gt;, visto che molte delle opzione usate da quest&amp;rsquo;ultimo plugin possono essere usate anche da SimpleForm.&lt;/p&gt;

&lt;h3&gt;Personalizzazione di SimpleForm&lt;/h3&gt;

&lt;p&gt;Quando prima abbiamo lanciato il generatore di SimpleForm, sono stati creati tre file:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rails g simple_form:install
    &lt;span class="passed"&gt;create&lt;/span&gt;  config/initializers/simple_form.rb
    &lt;span class="passed"&gt;create&lt;/span&gt;  config/locales/simple_form.en.yml
    &lt;span class="passed"&gt;create&lt;/span&gt;  lib/templates/erb/scaffold/_form.html.erb
&lt;/pre&gt;

&lt;p&gt;Se volessimo personalizzare SimpleForm per tutta un&amp;rsquo;applicazione (non solo per una singola form), potremmo farlo cambiando uno o pi&amp;ugrave; di questi tre file. Il primo contiene una serie di opzioni di configurazione commentate che si possono sfruttare per le personalizzazioni. Per esempio, potremmo cambiare l&amp;rsquo;ordine in cui ciascun campo viene mostrato; potremmo modificare componente container per ogni campo di form, cos&amp;igrave; come la dimensione di default del campo di testo. Vogliamo che i campi di testo della nostra applicazione siano pi&amp;ugrave; stretti, perci&amp;ograve; cambiamo il valore di default da &lt;code&gt;50&lt;/code&gt; a &lt;code&gt;30&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/simple_form.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
# Use this setup block to configure all options available in SimpleForm.
SimpleForm.setup do |config|

  # Other options removed...

  # Default size for text inputs.
  config.default_input_size = 30
end
&lt;/pre&gt;

&lt;p&gt;Il secondo file generato &amp;egrave; quello di I18n:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/locales/simple_form.en.yml&lt;/p&gt;
&lt;pre class="ruby"&gt;
en:
  simple_form:
    &amp;quot;yes&amp;quot;: &amp;#x27;Yes&amp;#x27;
    &amp;quot;no&amp;quot;: &amp;#x27;No&amp;#x27;
    required:
      text: &amp;#x27;required&amp;#x27;
      mark: &amp;#x27;*&amp;#x27;
      # You can uncomment the line below if you need to overwrite the whole required html.
      # When using html, text and mark won&amp;#x27;t be used.
      # html: &amp;#x27;&lt;abbr title="required"&gt;*&lt;/abbr&gt;&amp;#x27;
    error_notification:
      default_message: &amp;quot;Some errors were found, please take a look:&amp;quot;
    # Labels and hints examples
    # labels:
    #   password: &amp;#x27;Password&amp;#x27;
    #   user:
    #     new:
    #       email: &amp;#x27;E-mail para efetuar o sign in.&amp;#x27;
    #     edit:
    #       email: &amp;#x27;E-mail.&amp;#x27;
    # hints:
    #   username: &amp;#x27;User name to sign in.&amp;#x27;
    #   password: &amp;#x27;No special characters, please.&amp;#x27;
&lt;/pre&gt;    

&lt;p&gt;Anche se la vostra applicazione non ha bisogno di mostrarsi in pi&amp;ugrave; di una lingua, questo file resta comunque un punto pratico in cui modificare alcune delle opzioni di SimpleForm, come ad esempio il testo da mostrare in caso di errore su campi obbligatori.&lt;/p&gt; 

&lt;p&gt;L&amp;rsquo;ultimo file generato ridefinisce il partial della form per il generatore di scaffold:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/lib/templates/erb/scaffold/_form.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%%= simple_form_for(@&amp;lt;%= singular_name %&amp;gt;) do |f| %&amp;gt;
  &amp;lt;%% if @&amp;lt;%= singular_name %&amp;gt;.errors.any? %&amp;gt;
    &amp;lt;div id=&amp;quot;error_explanation&amp;quot;&amp;gt;
      &amp;lt;h2&amp;gt;&amp;lt;%%= pluralize(@&amp;lt;%= singular_name %&amp;gt;.errors.count, &amp;quot;error&amp;quot;) %&amp;gt; prohibited this &amp;lt;%= singular_name %&amp;gt; from being saved:&amp;lt;/h2&amp;gt;

      &amp;lt;ul&amp;gt;
      &amp;lt;%% @&amp;lt;%= singular_name %&amp;gt;.errors.full_messages.each do |msg| %&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;%%= msg %&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;%% end %&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;%% end %&amp;gt;

  &amp;lt;div class=&amp;quot;inputs&amp;quot;&amp;gt;
  &amp;lt;%- attributes.each do |attribute| -%&amp;gt;
    &amp;lt;%%= f.&amp;lt;%= attribute.reference? ? :association : :input %&amp;gt; :&amp;lt;%= attribute.name %&amp;gt; %&amp;gt;
  &amp;lt;%- end -%&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;
    &amp;lt;%%= f.button :submit %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;%% end %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;In Rails 3 possiamo fare l&amp;rsquo;override di un qualunque template in un generatore, aggiungendolo alla nostra applicazione, per cui se volessimo personalizzare il modo in cui un generatore funziona per adeguarlo al modo in cui noi vogliamo che funzioni, potremmo farlo semplicemente creando un nuovo file di template.&lt;/p&gt;

&lt;p&gt;E&amp;rsquo; tutto per questo episodio. SimpleForm rende ancor pi&amp;ugrave; semplice la creazione di form nelle vostre applicazioni Rails e vale la pena esaminarlo.&lt;/p&gt;</description>
      <pubDate>Sun, 31 Oct 2010 21:54:28 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/234-simple-form</guid>
      <link>http://it.asciicasts.com/episodes/234-simple-form</link>
    </item>
    <item>
      <title>Conosciamo Devise</title>
      <description>&lt;p&gt;Nella recente gara Rails Rumble i partecipanti hanno provato a creare un&amp;rsquo;applicazione Rails in 48 ore. La pagina di login alla competizione era interessante, perch&amp;egrave; permetteva di autenticarsi mediante una serie di servizi differenti.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/475/original/E233I01.png" width="804" height="716" alt="La pagina di login a Rails Rumble."/&gt;
&lt;/div&gt;

&lt;p&gt;Dare la possibilit&amp;agrave; di autenticarsi mediante una serie di servizi differenti pu&amp;ograve; richiedere uno sforzo notevole in termini di sviluppo, ma il sito Rails Rumble ha risolto il problema usando Janrain, che fornisce un servizio chiamato &lt;a href="http://www.janrain.com/products/engage"&gt;Janrain Engage&lt;/a&gt; (conosciuto anche come RPX). Si tratta di un servizio di autenticazione centralizzato; c&amp;rsquo;&amp;egrave; un API con cui una applicazione pu&amp;ograve; comunicare per abilitare l&amp;rsquo;autenticazione mediante una pletora di altri provider. Janrain &amp;egrave; un servizio commerciale, ma ne esiste anche una versione gratuita, pi&amp;ugrave; limitata, che va pi&amp;ugrave; che bene per gli scopi di un sito come Rails Rumble.&lt;/p&gt;

&lt;h3&gt;Autenticazione mediante Engage&lt;/h3&gt;

&lt;p&gt;L&amp;rsquo;autenticazione basilare mediante il servizio Janrain Engage &amp;agrave; semplice. Una volta registrati al servizio e aver fornito un nome per la nostra applicazione, veniamo portati alla home page del nostro account. Da qui dobbiamo prendere nota della chiave per le API e del nome dell&amp;rsquo;applicazione, in questo caso &amp;lsquo;asciicasts&amp;rsquo;. Dobbiamo anche dichiarare i provider che desideriamo usare. Se ci autentichiamo e poi clicchiamo sul tab &amp;lsquo;Providers&amp;rsquo;, veniamo portati a una pagina da cui potremo scegliere i servizi attraverso i quali gli utenti della nostra applicazione potranno autenticarsi:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/476/original/E233I02.png" width="802" height="582" alt="La scelta dei provider dei servizi di autenticazione  per la nostra applicazione."/&gt;
&lt;/div&gt;

&lt;p&gt;L&amp;rsquo;account gratuito consente solo di scegliere fra sei provider, ma gi&amp;agrave; questi sono sufficienti per darci un&amp;rsquo;ampia scelta. Si noti che alcuni di questi richiedono una configurazione extra. Per esempio, per usare Twitter, dovremmo configurare la nostra applicazione come un client OAuth, ma &amp;egrave; piuttosto semplice farlo. Per la nostra applicazione, useremo i quattro provider proposti per default.&lt;/p&gt;

&lt;h3&gt;Modifichiamo la nostra applicazione per usare Engage&lt;/h3&gt;

&lt;p&gt;Ora che ci siamo registrati, possiamo utilizzare Engage in un&amp;rsquo;applicazione Rails. Se stessimo creando un meccanismo di autenticazione partendo da zero,potremmo utilizzare il gem &lt;a href="http://github.com/grosser/rpx_now"&gt;RPXNow&lt;/a&gt;, che offre molte funzionalit&amp;agrave; per aiutarci a usare Engage nella nostra applicazione. Se la nostra applicazione usava gi&amp;agrave; Authlogic, esiste un gem denominato &lt;a href="http://github.com/tardate/authlogic_rpx"&gt;Authlogic RPX&lt;/a&gt;, che vale la pena di considerare. Infine c&amp;rsquo;&amp;egrave; il gem &lt;a href="http://github.com/slainer68/devise_rpx_connectable"&gt;RPX Connectable&lt;/a&gt; per l&amp;rsquo;utilizzo con Devise. L&amp;rsquo;applicazione con cui stiamo lavorando in questo episodio usa Devise, per cui utilizziamo proprio quest&amp;rsquo;ultimo gem per integrare Engage in esso. Se non conoscete bene Devise, date uno sguardo all&amp;rsquo;episodio 209 [&lt;a href="http://railscasts.com/episodes/209-introducing-devise"&gt;guardalo&lt;/a&gt;, &lt;a href="http://it.asciicasts.com/episodes/209-introduzione-a-devise"&gt;leggilo&lt;/a&gt;] per una breve presentazione.&lt;/p&gt;

&lt;p&gt;La nostra applicazione ha gi&amp;agrave; i collegamenti &amp;ldquo;Sign up&amp;rdquo; e &amp;ldquo;Sign in&amp;rdquo; che portano l&amp;rsquo;utente ad una semplice form da riempire con un indirizzo email e una password:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/477/original/E233I03.png" width="802" height="438" alt="L&amp;rsquo;attuale maschera di autenticazione della nostra applicazione."/&gt;
&lt;/div&gt;

&lt;p&gt;Vogliamo sostituire questi link con uno unico che conduce l&amp;rsquo;utente a una pagina dove pu&amp;ograve; autenticarsi mediante Engage ed &amp;egrave; proprio qui che potremo avvalerci del gem RPX Connectable.&lt;/p&gt; 

&lt;p&gt;Per usare il gem nella nostra applicazione dobbiamo innanzitutto aggiungerne il riferimento nel &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;
source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.0&amp;#x27;
gem &amp;#x27;sqlite3-ruby&amp;#x27;, &amp;#x27;1.2.5&amp;#x27;, :require =&amp;gt; &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;devise&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;devise_rpx_connectable&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;e poi installarla con:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ bundle install
&lt;/pre&gt;

&lt;p&gt;Per usare RPX, dobbiamo aggiungere un campo &lt;code&gt;rpx_identifier&lt;/code&gt; alla nostra tabella &lt;code&gt;Users&lt;/code&gt;. Genereremo una nuova migrazione per fare ci&amp;ograve;:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rails g migration add_rpx_to_users rpx_identifier:string
&lt;/pre&gt;

&lt;p&gt;Poi possiamo lanciare la migrazione per aggiungere il nuovo campo:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rake db:migrate
&lt;/pre&gt;

&lt;p&gt;Poi dobbiamo modificare la chiamata a &lt;code&gt;devise&lt;/code&gt; nella classe di modello &lt;code&gt;User&lt;/code&gt;, affinch&amp;egrave; abbia &lt;code&gt;:rpx_connectable&lt;/code&gt; nella sua lista di module:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class User &amp;lt; ActiveRecord::Base
  devise :database_authenticatable, :registerable, 
         :recoverable, :rememberable, :trackable, :validatable, :rpx_connectable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation
end
&lt;/pre&gt;

&lt;p&gt;Infine dobbiamo aggiornare il file di configurazione di Devise della nostra applicazione per indicare il nome che abbiamo utilizzato per la nostra applicazione quando ci siamo registrati per essa ad Engage, oltre alla chiave API che ci &amp;egrave; stata fornica:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/devise.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Devise.setup do |config|
  # Configure the e-mail address which will be shown in DeviseMailer.
  config.mailer_sender = &amp;quot;test@example.com&amp;quot;
  config.rpx_application_name = &amp;#x27;asciicasts&amp;#x27;
  RPXNow.api_key = &amp;quot;aaabbbcccdddeeefff&amp;quot; # real key goes here.
end
&lt;/pre&gt;

&lt;p&gt;Ora che abbiamo configurato tutto, possiamo sostituire i due link &amp;ldquo;Sign up&amp;rdquo; and &amp;ldquo;Sign in&amp;rdquo; nel file di layout con l&amp;rsquo;unico link alla pagina di autenticazione Engage, passando l&amp;rsquo;URL a cui vogliamo ritornare subito dopo l&amp;rsquo;autenticazione:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= link_to_rpx "Sign in", user_session_url %&amp;gt;
&lt;/pre&gt;

&lt;h3&gt;Autenticazione&lt;/h3&gt;

&lt;p&gt;Abbiamo tutto il codice in regola per provare ad autenticarci. Quando clicchiamo sul link di &amp;ldquo;Sign in&amp;rdquo; nella nostra applicazione, verremo ridiretti ad una pagina presente sui server di Janrain:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/478/original/E233I04.png" width="814" height="444" alt="Possiamo ora autenticarci con Engage."/&gt;
&lt;/div&gt;

&lt;p&gt;Possiamo ora autenticarci usando uno degli account proposti qui sopra e, nell&amp;rsquo;ipotesi che abbiamo inserito correttamente i nostri dati, saremo ridiretti alla nostra applicazione:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/479/original/E233I05.png" width="813" height="375" alt="Autenticati con successo mediante l&amp;rsquo;account di Google."/&gt;
&lt;/div&gt;

&lt;p&gt;Si noti che ora siamo autenticati nella nostra applicazione.&lt;/p&gt;

&lt;h3&gt;Una pagina di login migliore&lt;/h3&gt;

&lt;p&gt;Se volessimo che il pannello di log-in fosse pi&amp;ugrave; carino, facendolo diventare un overlay Javascript, anzich&amp;egrave; una pagina a parte, potremmo farlo includendo la seguente linea di codice subito prima del tag di chiusura del body nel file di layout:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= javascript_include_rpx(user_session_url) %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Ci&amp;ograve; aggiunger&amp;agrave; del JavaScript alla nostra applicazione, che mostrer&amp;agrave; un overlay sul sito quando uno tenta di autenticarsi:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/480/original/E233I06.png" width="813" height="413" alt="L&amp;rsquo;uso di un pannello in popup per l&amp;rsquo;autenticazione."/&gt;
&lt;/div&gt;

&lt;p&gt;In alternativa potremmo inserire il pannello di autenticazione ovunque nella nostra applicazione, usando un iframe. Per farlo, tutto ci&amp;ograve; che dovremmo fare sarebbe di aggiungere la seguente linea di codice da qualche parte nel codice della vista:&lt;/p&gt;

&lt;pre class="ruby"&gt;
&amp;lt;%= embed_rpx user_session_url %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Questo codice &amp;egrave; bene metterlo da qualche parte vicino alla maschera di login, per consentire un metodo alternativo di autenticazione.&lt;/p&gt;

&lt;p&gt;Tutto ci&amp;ograve; che vi abbiamo mostrato in questo episodio si trova nel file README di Devise RPX Connectable, insieme ad alcune informazioni su certe opzioni aggiuntive  che possono essere passate affinch&amp;egrave; sia possibile richiedere informazioni aggiuntive su ciascun utente autenticato.&lt;/p&gt;</description>
      <pubDate>Wed, 13 Oct 2010 21:46:06 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/233-conosciamo-devise</guid>
      <link>http://it.asciicasts.com/episodes/233-conosciamo-devise</link>
    </item>
    <item>
      <title>Esploriamo il routing di Rails 3 (parte 2)</title>
      <description>&lt;p&gt;In questo episodio continueremo da dove eravamo rimasti la settimana scorsa e riprenderemo a esaminare il codice interno di Rails 3 deputato al routing. Al termine dello scorso episodio, il file di route appariva pi&amp;ugrave; o meno cos&amp;igrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  match &amp;#x27;products&amp;#x27;, :to =&amp;gt; ProductsController.action(&amp;quot;index&amp;quot;)
  match &amp;#x27;products/recent&amp;#x27;
end
&lt;/pre&gt;

&lt;p&gt;L&amp;rsquo;ultima volta abbiamo visto il codice interno del metodo &lt;code&gt;match&lt;/code&gt; e abbiamo scoperto cosa accade quando si invoca il &lt;code&gt;match&lt;/code&gt; nel file di route, tuttavia ci sono diversi altri metodi che possiamo richiamare che vedremo proprio in questo episodio.&lt;/p&gt;

&lt;p&gt;Esaminando il codice sorgente di Rails 3.0, ritroviamo le logiche di routing nella cartella &lt;code&gt;actionpack/lib/actiondispatch/routing&lt;/code&gt;. Ci focalizzeremo sulla classe &lt;code&gt;Mapper&lt;/code&gt; presente in tale cartella poich&amp;egrave;, come gi&amp;agrave; discusso la volta scorsa, il blocco presente all&amp;rsquo;interno del file di route &amp;egrave; inquadrato nell&amp;rsquo;ambito di questa classe. In altre parole, ogni metodo richiamato all&amp;rsquo;interno del blocco &amp;egrave; chiamato su di un&amp;rsquo;istanza di &lt;code&gt;Mapper&lt;/code&gt;, ragion per cui possiamo richiamare un qualsiasi metodo di istanza della classe &lt;code&gt;Mapper&lt;/code&gt; all&amp;rsquo;interno del nostro file di route.&lt;/p&gt;

&lt;p&gt;Il codice della classe &lt;code&gt;Mapper&lt;/code&gt; pu&amp;ograve; apparire un po&amp;rsquo; destabilizzante. Il codice &amp;egrave; tanto, quasi 1000 linee, e complesso, ma la buona notizia &amp;egrave; che si tratta in effetti del file pi&amp;ugrave; verboso per quel che concerne il routing di Rails, per cui se riuscirete ad afferrare le logiche che intercorrono in questo file e a capirle, vi sarete fatti un&amp;rsquo;idea piuttosto buona del funzionamento interno complessivo del routing in Rails.&lt;/p&gt;

&lt;p&gt;Al fine di ottenere una buona vista di insieme del codice, collasseremo il corpo dei metodi. In TextMate la pressione dei tasti &lt;code&gt;Command-Option-0&lt;/code&gt; causer&amp;agrave; appunto il collassamento di tutto quanto &amp;egrave; collassabile all&amp;rsquo;interno del file. Fatto ci&amp;ograve; espandiamo il module di radice &lt;code&gt;ActionDispatch&lt;/code&gt;, il suo sottomodulo &lt;code&gt;Routing&lt;/code&gt; ed infine la classe &lt;code&gt;Mapping&lt;/code&gt; stessa, per avere un quadro della sua struttura:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/474/original/E232I01.png" width="732" height="798" alt="La struttura della classe Mapper."/&gt;
&lt;/div&gt;

&lt;p&gt;I primi due elementi nella classe &lt;code&gt;Mapper&lt;/code&gt; sono la definizione delle classi &lt;code&gt;Constraints&lt;/code&gt; e &lt;code&gt;Mapping&lt;/code&gt;. Le abbiamo viste entrambe nell&amp;rsquo;ultimo episodio, ma ci&amp;ograve; che &amp;egrave; significativo notare qui &amp;egrave; come queste siano innestate sotto alla classe &lt;code&gt;Mapper&lt;/code&gt;. Tutto ci&amp;ograve; potrebbe apparire strano se vi siete appena avvicinati a Ruby e vi potreste giustamente domandare perch&amp;egrave; dovreste aver bisogno di innestare le classi in un modo simile. Nulla di magico: la classe &lt;code&gt;Constraints&lt;/code&gt; &amp;egrave; completamente separata dalla classe &lt;code&gt;Mapper&lt;/code&gt;. La ragione per cui &amp;egrave; stata realizzata una simile struttura &amp;egrave; che l&amp;rsquo;innestamento delle classi definisce il namespace per le classi &lt;code&gt;Constraints&lt;/code&gt; e &lt;code&gt;Mapping&lt;/code&gt; in modo tale che queste appaiano sotto il namespace di &lt;code&gt;Mapper&lt;/code&gt;. Non c&amp;rsquo;&amp;egrave; alcuna ereditariet&amp;agrave; o condivisione di comportamento quando si realizzano simili innestamenti di classi in Ruby.&lt;/p&gt; 

&lt;p&gt;Spostandoci pi&amp;ugrave; in basso, troviamo due metodi di classe, &lt;code&gt;self.normalize_path&lt;/code&gt; e &lt;code&gt;self.normalize_name&lt;/code&gt;. Si tratta di metodi di utilit&amp;agrave; che sono utilizzati frequentemente all&amp;rsquo;interno della classe. Sotto di questi, c&amp;rsquo;&amp;egrave; un insieme di module:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
module Base...

module HttpHelpers...

module Scoping...

module Resources...

module Shorthand...

include Base
include HttpHelpers
include Scoping
include Resources
include Shorthand
&lt;/pre&gt;

&lt;p&gt;Questi cinque module sono inclusi nella classe &lt;code&gt;Mapper&lt;/code&gt;. Il codice al loro interno &amp;egrave; stato confinato in module semplicemente per pulizia.&lt;/p&gt; 

&lt;h3&gt;Base&lt;/h3&gt;

&lt;p&gt;Abbiamo visto il primo module, &lt;code&gt;Base&lt;/code&gt;, nell&amp;rsquo;ultimo episodio. Contiene il metodo &lt;code&gt;match&lt;/code&gt;, il metodo &lt;code&gt;root&lt;/code&gt; che utilizza &lt;code&gt;match&lt;/code&gt; e anche un metodo &lt;code&gt;mount&lt;/code&gt; che fornisce un altro modo di mappare un&amp;rsquo;applicazione Rack ad un URL:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
module Base
  def initialize(set) #:nodoc:

  def root(options = {})
    match &amp;#x27;/&amp;#x27;, options.reverse_merge(:as =&amp;gt; :root)
  end

  def match(path, options=nil)...

  def mount(app, options = nil)...

  def default_url_options=(options)...
  alias_method :default_url_options, :default_url_options=
end
&lt;/pre&gt;

&lt;h3&gt;HttpHelpers&lt;/h3&gt;

&lt;p&gt;Il module successivo &amp;egrave; &lt;code&gt;HttpHelpers&lt;/code&gt;, all&amp;rsquo;interno del quale sono definiti i metodi &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt; e &lt;code&gt;delete&lt;/code&gt;. Questi metodi sono usati per mappare i route a determinati tipi di richieste:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
module HttpHelpers
  def get(*args, &amp;amp;block)
    map_method(:get, *args, &amp;amp;block)
  end

  def post(*args, &amp;amp;block)
    map_method(:post, *args, &amp;amp;block)
  end

  def put(*args, &amp;amp;block)
    map_method(:put, *args, &amp;amp;block)
  end

  def delete(*args, &amp;amp;block)
    map_method(:delete, *args, &amp;amp;block)
  end

  def redirect(*args, &amp;amp;block)...

  private
  def map_method(method, *args, &amp;amp;block)
     options = args.extract_options!
     options[:via] = method
     args.push(options)
     match(*args, &amp;amp;block)
     self
   end
end
&lt;/pre&gt;

&lt;p&gt;Tutti questi metodi al loro interno chiamano il metodo privato &lt;code&gt;map_method&lt;/code&gt;. Questo metodo imposta l&amp;rsquo;opzione &lt;code&gt;:via&lt;/code&gt; a seconda del metodo passatogli e infine chiama il metodo &lt;code&gt;match&lt;/code&gt;. Noterete nel vostro codice di routing che molti dei metodi delegano al metodo &lt;code&gt;match&lt;/code&gt;, passandogli e personalizzando a priori determinate opzioni. Per cui, se vogliamo che un certo route risponda solo a una richiesta GET, potremmo scrivere, usando l&amp;rsquo;opzione &lt;code&gt;via&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="ruby"&gt;
match &amp;#x27;products/recent&amp;#x27;, :via =&amp;gt; :get
&lt;/pre&gt;

&lt;p&gt;All&amp;rsquo;atto pratico, facciamo la stessa cosa usando il metodo pi&amp;ugrave; conciso &lt;code&gt;get&lt;/code&gt;, che crea proprio un route con la stessa opzione:&lt;/p&gt;

&lt;pre class="ruby"&gt;
get &amp;#x27;products/recent&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;I metodi &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt; e &lt;code&gt;delete&lt;/code&gt; funzionano in modo analogo al get per gli altri tipi di richieste HTTP. Il metodo &lt;code&gt;redirect&lt;/code&gt;, invece, si differenzia dagli altri ed &amp;egrave; interessante perch&amp;egrave; restituisce un&amp;rsquo;applicazione Rack:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def redirect(*args, &amp;amp;block)
  options = args.last.is_a?(Hash) ? args.pop : {}

  path      = args.shift || block
  path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
  status    = options[:status] || 301

  lambda do |env|
    req = Request.new(env)

    params = [req.symbolized_path_parameters]
    params &amp;lt;&amp;lt; req if path_proc.arity &amp;gt; 1

    uri = URI.parse(path_proc.call(*params))
    uri.scheme ||= req.scheme
    uri.host   ||= req.host
    uri.port   ||= req.port unless req.standard_port?

    body = %(&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;You are being &amp;lt;a href=&amp;quot;#{ERB::Util.h(uri.to_s)}&amp;quot;&amp;gt;redirected&amp;lt;/a&amp;gt;.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;)

    headers = {
      &amp;#x27;Location&amp;#x27; =&amp;gt; uri.to_s,
      &amp;#x27;Content-Type&amp;#x27; =&amp;gt; &amp;#x27;text/html&amp;#x27;,
      &amp;#x27;Content-Length&amp;#x27; =&amp;gt; body.length.to_s
    }

    [ status, headers, [body] ]
  end
end
&lt;/pre&gt;

&lt;p&gt;Il metodo restituisce un&amp;rsquo;applicazione Rack, restituendo un array comprendente uno stato, alcuni elementi di header e un body. Lo stato &amp;egrave; impostato per default a &lt;code&gt;301&lt;/code&gt; che impone al browser un semplice redirect &lt;code&gt;301 Moved Permanently&lt;/code&gt;. Potremmo usare questo metodo &lt;code&gt;redirect&lt;/code&gt; direttamente all&amp;rsquo;interno del nostro file di route se volessimo che un URL ridirigesse ad un altro. Nel nostro file di route abbiamo gi&amp;agrave; un route che utilizza il parametro &lt;code&gt;:to&lt;/code&gt; e questo parametro accetta un&amp;rsquo;applicazione Rack:&lt;/p&gt;

&lt;pre class="ruby"&gt;
match &amp;#x27;products&amp;#x27;, :to =&amp;gt; ProductsController.action(&amp;quot;index&amp;quot;)
&lt;/pre&gt;

&lt;p&gt;Dato che il metodo &lt;code&gt;redirect&lt;/code&gt; restituisce un&amp;rsquo;applicazione Rack, lo possiamo usare in questo caso per fare un redirect a un altro URL in questo modo:&lt;/p&gt;

&lt;pre class="ruby"&gt;
match &amp;#x27;products&amp;#x27;, :to =&amp;gt; redirect(&amp;quot;/items&amp;quot;)
&lt;/pre&gt;

&lt;p&gt;Questa funzionalit&amp;agrave; diventa davvero utile nel momento in cui si decide di modificare gli URL dell&amp;rsquo;applicazione, ma si desidera continuare a fornire supporto agli URL vecchi. Si pu&amp;ograve; usare &lt;code&gt;redirect&lt;/code&gt; per ridirigere questi URL ai nuovi ad essi corrispondenti.&lt;/p&gt;

&lt;h3&gt;Shorthand&lt;/h3&gt;

&lt;p&gt;I moduli successivi sarebbero &lt;code&gt;Scoping&lt;/code&gt; e &lt;code&gt;Resources&lt;/code&gt;, ma li vediamo fra poco. Per ora, focalizziamoci sul module &lt;code&gt;Shorthand&lt;/code&gt;. E&amp;rsquo; un module interessante che ridefinisce il metodo &lt;code&gt;match&lt;/code&gt;, che era stato precedentemente definito nel module &lt;code&gt;Base&lt;/code&gt;. Questo metodo &lt;code&gt;match&lt;/code&gt; supporta una sintassi diversa per le opzioni che &amp;egrave; possibile passargli. Il metodo shorthand rappresenta un modo alternativo per scrivere l&amp;rsquo;opzione &lt;code&gt;:to&lt;/code&gt; in un route tipo il &lt;code&gt;redirect&lt;/code&gt; che abbiamo scritto poc&amp;rsquo;anzi:&lt;/p&gt;

&lt;pre class="ruby"&gt;
match &amp;#x27;products&amp;#x27;, :to =&amp;gt; redirect(&amp;#x27;/items&amp;#x27;)
&lt;/pre&gt;

&lt;p&gt;Si tratta di una sintassi comune nei file di route. Il metodo shorthand ci permette di scrivere il route con un semplice hash fatto dal route e da qualunque cosa a cui il route debba puntare. Come si pu&amp;ograve; fare con la sintassi estesa, &amp;egrave; possibile aggiungere parametri in coda al route:&lt;/p&gt;

&lt;pre class="ruby"&gt;
match &amp;#x27;products&amp;#x27; =&amp;gt; redirect(&amp;#x27;/items&amp;#x27;)
&lt;/pre&gt;

&lt;p&gt;Il metodo match ridefinito in &lt;code&gt;Shorthand&lt;/code&gt; imposta il parametro &lt;code&gt;:to&lt;/code&gt; se non &amp;egrave; ancora stato impostato. Poi chiama il &lt;code&gt;super&lt;/code&gt;, ma dal momento che &lt;code&gt;Mapper&lt;/code&gt; non eredita da un&amp;rsquo;altra classe, cosa comporta, in questo caso, la chiamata a &lt;code&gt;super&lt;/code&gt;?&lt;/p&gt;

&lt;p class="ruby"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
module Shorthand
  def match(*args)
    if args.size == 1 &amp;amp;&amp;amp; args.last.is_a?(Hash)
      options  = args.pop
      path, to = options.find { |name, value| name.is_a?(String) }
      options.merge!(:to =&amp;gt; to).delete(path)
      super(path, options)
    else
      super
    end
  end
end
&lt;/pre&gt;

&lt;p&gt;Ogni volta che si usa &lt;code&gt;super&lt;/code&gt; in questo modo, Ruby cerca un metodo con lo stesso nome che sia stato definito in un module a monte. Il module &lt;code&gt;Shorthand&lt;/code&gt; &amp;egrave; definito come ultimo nella lista di module inclusi nel &lt;code&gt;Mapper&lt;/code&gt;, per cui Ruby controller&amp;agrave; nei module precedenti alla ricerca di un metodo &lt;code&gt;match&lt;/code&gt; e delegher&amp;agrave; ad esso. In questo caso chiamer&amp;agrave; il &lt;code&gt;match&lt;/code&gt; presente nel module Base.&lt;/p&gt;

&lt;p&gt;Questa tecnica &amp;egrave; usata spesso nel codice sorgente di Rails 3. Le prime versioni di Rails usavano l&amp;rsquo;&lt;code&gt;alias_method_chain&lt;/code&gt; per ridefinire comportamenti specifici, ma ora, in Rails 3, possiamo pi&amp;ugrave; semplicemente usare il &lt;code&gt;super&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Resources&lt;/h3&gt;

&lt;p&gt;Chiuso il discorso sul module &lt;code&gt;Shorthand&lt;/code&gt;, ci occuperemo ora del &lt;code&gt;Resources&lt;/code&gt;. Come ci si potrebbe aspettare, questo module contiene il metodo &lt;code&gt;resources&lt;/code&gt; e tutti i metodi ad esso associati. Usiamo il metodo &lt;code&gt;resources&lt;/code&gt; nel nostro file di route per creare route RESTful:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;

&lt;pre class="ruby"&gt;
def resources(*resources, &amp;amp;block)
  options = resources.extract_options!

  if apply_common_behavior_for(:resources, resources, options, &amp;amp;block)
    return self
  end

  resource_scope(Resource.new(resources.pop, options)) do
    yield if block_given?

    collection_scope do
      get  :index if parent_resource.actions.include?(:index)
      post :create if parent_resource.actions.include?(:create)
    end

    new_scope do
      get :new
    end if parent_resource.actions.include?(:new)

    member_scope  do
      get    :edit if parent_resource.actions.include?(:edit)
      get    :show if parent_resource.actions.include?(:show)
      put    :update if parent_resource.actions.include?(:update)
      delete :destroy if parent_resource.actions.include?(:destroy)
    end
  end

  self
end
&lt;/pre&gt;

&lt;p&gt;Questo metodo &amp;egrave; piuttosto complesso, ma osservandone la struttura generale assume un certo significato. Ci sono un paio di metodi di collezione, &lt;code&gt;get :index&lt;/code&gt; e &lt;code&gt;post :create&lt;/code&gt;; c&amp;rsquo;&amp;egrave; un metodo &lt;code&gt;get :new&lt;/code&gt; e infine &lt;code&gt;get :edit&lt;/code&gt;, &lt;code&gt;get :show&lt;/code&gt;, &lt;code&gt;put :update&lt;/code&gt; e &lt;code&gt;delete :destroy&lt;/code&gt;. Dovreste riconoscere questi come le famose sette action RESTful che sono create per un controller quando si dichiara resources per esso nel file di route.&lt;/p&gt; 

&lt;p&gt;Si noti la prima linea di codice nel blocco del metodo &lt;code&gt;resource_scope&lt;/code&gt;. Se viene passato un blocco al metodo, di conseguenza il metodo far&amp;agrave; &lt;code&gt;yield&lt;/code&gt; a tale blocco prima di creare le action RESTful. Tutto ci&amp;ograve; ci consente di creare le nostre action personalizzate nel file di route. Per esempio, potremmo aggiungere un route di collection che restituisce i prodotti in sconto:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  match &amp;#x27;products&amp;#x27;, :to =&amp;gt; redirect(&amp;#x27;/items&amp;#x27;)
  get &amp;#x27;products/recent&amp;#x27;
  resources :products do
    collection do:
      get :discounted
    end
  end
end
&lt;/pre&gt;

&lt;p&gt;Il codice dentro al blocco passato a &lt;code&gt;resources&lt;/code&gt; nel route riportato qui sopra verr&amp;agrave; eseguito dalla chiamata a &lt;code&gt;yield&lt;/code&gt; in &lt;code&gt;resource_scope&lt;/code&gt; e successivamente verranno definite le action RESTful standard. Nel blocco riportato qui sopra possiamo usare codice simile a quello presente nel metodo resources dei sorgenti di Rails, per definire le nostre action personalizzate.&lt;/p&gt;

&lt;p&gt;Guardando i blocchi, nel file di route di sopra riportato, potreste essere indotti a pensare che l&amp;rsquo;oggetto cambi ogni volta che si crea un nuovo blocco, ma non &amp;egrave; cos&amp;igrave;. Stiamo ancora lavorando con lo stesso oggetto &lt;code&gt;Mapper&lt;/code&gt; con cui abbiamo lavorato all&amp;rsquo;inizio, per cui chiamare &lt;code&gt;get&lt;/code&gt; nel blocco pi&amp;ugrave; innestato esegue esattamente la stessa cosa che eseguirebbe richiamandolo dal pi&amp;ugrave; esterno. La sola cosa che cambia &amp;egrave; che siamo in uno scope differente, ma nel parleremo a breve di questo.&lt;/p&gt;

&lt;p&gt;Se tornate a esaminare il metodo &lt;code&gt;resources&lt;/code&gt; del codice sorgente di Rails, vedrete che il codice utilizza una chiamata &lt;code&gt;collection_scope&lt;/code&gt; quando definisce le action &lt;code&gt;index&lt;/code&gt; e &lt;code&gt;create&lt;/code&gt;, mentre all&amp;rsquo;interno dei nostri file di route utilizziamo semplicemente &lt;code&gt;collection&lt;/code&gt;. Che differenza c&amp;rsquo;&amp;egrave;? Beh, in realt&amp;agrave; non molta. Se diamo un&amp;rsquo;occhiata al metodo &lt;code&gt;collection&lt;/code&gt; nella classe &lt;code&gt;Mapper&lt;/code&gt;, vedremo che questi delega proprio a &lt;code&gt;collection_scope&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def collection
  unless @scope[:scope_level] == :resources
    raise ArgumentError, &amp;quot;can&amp;#x27;t use collection outside resources scope&amp;quot;
  end

  collection_scope do
    yield
  end
end
&lt;/pre&gt;

&lt;p&gt;Riguardiamo rapidamente il file di route:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  match &amp;#x27;products&amp;#x27;, :to =&amp;gt; redirect(&amp;#x27;/items&amp;#x27;)
  get &amp;#x27;products/recent&amp;#x27;
  resources :products do
    collection do:
      get :discounted
    end
  end
end
&lt;/pre&gt;

&lt;p&gt;Entrambe le chiamate a get nel codice di sopra invocano lo stesso metodo, ma quello che invoca da dentro il blocco &lt;code&gt;collection&lt;/code&gt; assumer&amp;agrave; un po&amp;rsquo; di comportamento aggiuntivo a seconda dello scope in cui si trova all&amp;rsquo;interno dei blocchi &lt;code&gt;resources&lt;/code&gt; e &lt;code&gt;collection&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se torniamo a vedere il module &lt;code&gt;Resources&lt;/code&gt;, vedremo un metodo familiare: &lt;code&gt;match&lt;/code&gt;. Questo metodo ridefinisce il metodo &lt;code&gt;match&lt;/code&gt;, aggiungendo un po&amp;rsquo; di comportamento aggiuntivo in base a resources:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def match(*args)
  options = args.extract_options!.dup
  options[:anchor] = true unless options.key?(:anchor)

  if args.length &amp;gt; 1
    args.each { |path| match(path, options.dup) }
    return self
  end

  on = options.delete(:on)
  if VALID_ON_OPTIONS.include?(on)
    args.push(options)
    return send(on){ match(*args) }
  elsif on
    raise ArgumentError, &amp;quot;Unknown scope #{on.inspect} given to :on&amp;quot;
  end

  if @scope[:scope_level] == :resources
    args.push(options)
    return nested { match(*args) }
  elsif @scope[:scope_level] == :resource
    args.push(options)
    return member { match(*args) }
  end

  action = args.first
  path = path_for_action(action, options.delete(:path))

  if action.to_s =~ /^[\w\/]+$/
    options[:action] ||= action unless action.to_s.include?(&amp;quot;/&amp;quot;)
    options[:as] = name_for_action(action, options[:as])
  else
    options[:as] = name_for_action(options[:as])
  end

  super(path, options)
end
&lt;/pre&gt;

&lt;p&gt;Se osserviamo, circa a met&amp;agrave; del codice qui sopra riportato, vedremo la linea di codice che verifica lo scope attuale per vedere se &amp;egrave; &lt;code&gt;resources&lt;/code&gt;. Se lo &amp;egrave;, viene aggiunto un po&amp;rsquo; di comportamento differente. La logica &amp;egrave; piuttosto complessa; tutto quello che dovete sapere &amp;egrave; che il module &lt;code&gt;Resources&lt;/code&gt; ridefinisce il metodo &lt;code&gt;match&lt;/code&gt;. Si noti che alla fine chiama &lt;code&gt;super&lt;/code&gt; affinch&amp;egrave; sia invocato il metodo &lt;code&gt;match&lt;/code&gt; del module &lt;code&gt;Base&lt;/code&gt;. Si tenga presente che il metodo &lt;code&gt;get&lt;/code&gt; invoca il &lt;code&gt;match&lt;/code&gt; ed &amp;egrave; qui che si trova la logica addizionale per gestire la &lt;code&gt;get&lt;/code&gt; e gli altri metodi che sono definiti in &lt;code&gt;resources&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Scoping&lt;/h3&gt;

&lt;p&gt;Siamo ora giuti all&amp;rsquo;ultimo metodo della classe &lt;code&gt;Mapping&lt;/code&gt;: &lt;code&gt;Scoping&lt;/code&gt;. Ovunque vi sia un blocco, all&amp;rsquo;interno dei vostri file di route, dietro le quinte c&amp;rsquo;&amp;egrave; anche una chiamata al metodo &lt;code&gt;scope&lt;/code&gt; di &lt;code&gt;Scoping&lt;/code&gt;. Ci&amp;ograve; significa che questi definir&amp;agrave; del comportamento addizionale per il codice presente all&amp;rsquo;interno del blocco.&lt;/p&gt; 

&lt;p&gt;Oltre al metodo scope, ci sono una serie di altri metodi, che delegano tutti a &lt;code&gt;scope&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def initialize(*args) #:nodoc:
  @scope = {}
  super
end

def controller(controller, options={})
  options[:controller] = controller
  scope(options) { yield }
end

def namespace(path, options = {})
  path = path.to_s
  options = { :path =&amp;gt; path, :as =&amp;gt; path, :module =&amp;gt; path,
              :shallow_path =&amp;gt; path, :shallow_prefix =&amp;gt; 			path }.merge!(options)
  scope(options) { yield }
end

def constraints(constraints = {})
  scope(:constraints =&amp;gt; constraints) { yield }
end

def defaults(defaults = {})
  scope(:defaults =&amp;gt; defaults) { yield }
end
&lt;/pre&gt;

&lt;p&gt;Questi metodi sono tutti abbastanza semplici e delegano tutti ad un metodo pi&amp;ugrave; generico, previa impostazione di alcune opzioni. Per esempio, &lt;code&gt;defaults&lt;/code&gt; chiama &lt;code&gt;scope&lt;/code&gt; dopo aver settato alcune opzioni &lt;code&gt;defaults&lt;/code&gt;. Analogamente, &lt;code&gt;constraints&lt;/code&gt; invoca scope impostando alcune opzioni &lt;code&gt;constraints&lt;/code&gt;. Il metodo &lt;code&gt;namespace&lt;/code&gt; &amp;egrave; un po&amp;rsquo; pi&amp;ugrave; complesso, ma fa sostanzialmente la stessa cosa. Il module ha anche un metodo &lt;code&gt;initialize&lt;/code&gt; che crea semplicemente una variabile di istanza &lt;code&gt;@scope&lt;/code&gt; e la imposta per essere un hash vuoto. Vi potreste ancora domandare cosa ci fa in un module un metodo &lt;code&gt;initialize&lt;/code&gt;. Anche in questo caso, nel module si sta facendo l&amp;rsquo;override di un metodo che sar&amp;agrave; in realt&amp;agrave; definito nella classe che include tale module. Quando il module &lt;code&gt;Scoping&lt;/code&gt; viene incluso nella classe &lt;code&gt;Mapper&lt;/code&gt; questo metodo &lt;code&gt;initialize&lt;/code&gt; ridefinir&amp;agrave; quello definito nel metodo &lt;code&gt;initialize&lt;/code&gt;, aggiungendo la variabile &lt;code&gt;@scope&lt;/code&gt; e poi richiamando il &lt;code&gt;super&lt;/code&gt;.&lt;/p&gt; 

&lt;p&gt;Infine abbiamo il metodo &lt;code&gt;scope&lt;/code&gt;, dove viene fatto il lavoro sporco. C&amp;rsquo;&amp;egrave; molta complessit&amp;agrave; in questo metodo, ma sostanzialmente tutto ci&amp;ograve; che fa &amp;egrave; riempire la variabile &lt;code&gt;@scope&lt;/code&gt; con alcune informazioni, basandosi sulle opzioni che sono state passate nello scope. Il metodo unisce le opzioni usando una serie di metodi privati nel module. Tutto ci&amp;ograve; che fa &amp;egrave; di immagazzinare l&amp;rsquo;informazione di scope affinch&amp;egrave; possa essere utilizzata successivamente all&amp;rsquo;interno di qualsiasi chiamata match abbiata. Sostanzialmente aggiunge utleriori funzionalit&amp;agrave; in base allo scope corrente.&lt;/p&gt; 

&lt;p&gt;Ecco come funzionano, fondamentalmente, i blocchi definiti all&amp;rsquo;interno dei file di route. Se definiamo un route del genere:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  controller :products do
    match #...
  end  
end
&lt;/pre&gt;

&lt;p&gt;Ogni volta che chiamiamo &lt;code&gt;match&lt;/code&gt; nel blocco &lt;code&gt;controller&lt;/code&gt; (e si ricordi che questi delega allo &lt;code&gt;scope&lt;/code&gt;) le opzioni del &lt;code&gt;controller&lt;/code&gt; saranno automaticamente fornite all&amp;rsquo;interno di questi.&lt;/p&gt;

&lt;p&gt;E&amp;rsquo; tutto per questo episodio. Spero che tutto ci&amp;ograve; vi abbia chiarito meglio di come siano trattati i metodi all&amp;rsquo;interno del file di route. Anche se esistono molti metodi fra cui scegliere all&amp;rsquo;interno del file di route, molti di questi sono semplici deleganti o al metodo match o allo scope, che passano in pi&amp;ugrave; solo alcune opzioni.&lt;/p&gt;</description>
      <pubDate>Wed, 13 Oct 2010 21:41:07 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/232-esploriamo-il-routing-di-rails-3-parte-2</guid>
      <link>http://it.asciicasts.com/episodes/232-esploriamo-il-routing-di-rails-3-parte-2</link>
    </item>
    <item>
      <title>Esploriamo il routing di Rails 3</title>
      <description>&lt;p&gt;L&amp;rsquo;episodio di questa settimana sar&amp;agrave; un po&amp;rsquo; diverso. Andremo infatti ad esplorare le parti interne di Rails 3 e a spulciare fra il suo codice, focalizzandoci su quello che gestisce il routing. Qui sotto &amp;egrave; riportato il file di route dell&amp;rsquo;applicazione del negozio virtuale dell&amp;rsquo;ultimo episodio. Per poter sapere ci&amp;ograve; che fa di fatto questo codice di routing, daremo un&amp;rsquo;occhiata al codice Rails che viene richiamato quando lo si lancia:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  resources :products do
    resources :reviews
  end
  root :to =&amp;gt; &amp;quot;products#index&amp;quot;
end
&lt;/pre&gt;

&lt;p&gt;Potreste domandarvi quale sia il punto di tutto ci&amp;ograve; e se serva a qualcosa andare a vedere del codice non nostro, ma secondo me leggere codice Ruby scritto da altri &amp;egrave; un eccellente modo di migliorare le proprie competenze in Ruby. Vedrete trucchi e tecniche che altri usano e che potrete in seguito riciclare per il vostro codice. Leggere il codice sorgente di Rails &amp;egrave; anche un buon modo per imparare ad usare meglio Rails e proprio in questa occasione potremo scoprire modi migliori di scrivere il file di routing. Se avete intenzione di provare a debuggare un problema o di ottimizzare del codice in uno dei vostri progetti, o se state persino per considerare seriamente l&amp;rsquo;idea di contribuire a Rails, allora leggere le sue parti interne rappresenta un ottimo modo per cominciare.&lt;/p&gt;

&lt;h3&gt;Partiamo&lt;/h3&gt;

&lt;p&gt;Questo episodio tratter&amp;agrave; alcuni aspetti avanzati, per cui si assume che conosciate gi&amp;agrave; il funzionamento del routing in Rails 3. Se cos&amp;igrave; non fosse, o se voleste rinfrescare le vostre conoscenze in merito, potreste &lt;a href="http://railscasts.com/episodes/203-routing-in-rails-3"&gt;guardare&lt;/a&gt; o &lt;a href="http://it.asciicasts.com/episodes/203-routing-in-rails-3"&gt;leggere&lt;/a&gt; l&amp;rsquo;episodio 203 prima di questo, considerato anche che la sintassi di Rails 3 differisce abbastanza rispetto a Rails 2.&lt;/p&gt;

&lt;p&gt;Il codice sorgente di Rails &amp;egrave; conservato su &lt;a href="http://github.com/rails/rails"&gt;Github&lt;/a&gt; ed &amp;egrave; semplice clonare il repository per consultare il codice contenutovi. Dobbiamo solo lanciare:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ git clone git://github.com/rails/rails.git
&lt;/pre&gt;

&lt;p&gt;Il branch master del repository che abbiamo scaricato &amp;egrave; per Rails 3.1, che &amp;egrave; la versione attualemente in sviluppo, ma noi vogliamo consultare i sorgenti della stessa versione su cui gira la nostra applicazione. Possiamo spostarci alla versione taggata 3.0.0 lanciando:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ git checkout v3.0.0
&lt;/pre&gt;

&lt;p&gt;Aprendo la cartella di Rails notiamo subito che Rails &amp;egrave; composto da tante parti differenti. Tutto ci&amp;ograve; che concerne i controller, le viste o i route, si trova sotto la cartella &lt;code&gt;actionpack&lt;/code&gt;, per cui &amp;egrave; questa la parte del codice che ci interessa:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/472/original/E231I01.png" width="795" height="454" alt="La struttura delle cartelle del codice sorgente di Rails."/&gt;
&lt;/div&gt;

&lt;p&gt;Sotto &lt;code&gt;actionpack&lt;/code&gt; la maggior parte del codice riguardante il routing &amp;egrave; sotto la cartella &lt;code&gt;lib/action_dispatch&lt;/code&gt;:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/473/original/E231I02.png?1284930544" width="796" height="540" alt="La struttura della cartella actionpack che mostra i file di routing."/&gt;
&lt;/div&gt;

&lt;h3&gt;I metodi &lt;code&gt;routes&lt;/code&gt; e &lt;code&gt;draw&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Prima di cominciare a guardare il codice sorgente di Rails, ritorniamo alla nostra applicazione e guardiamo nuovamente il file di route:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  resources :products do
    resources :reviews
  end
  root :to =&amp;gt; &amp;quot;products#index&amp;quot;
end
&lt;/pre&gt;

&lt;p&gt;La prima linea del codice riportato di sopra chiama un metodo chiamato routes sulla classe &lt;code&gt;Store::Application&lt;/code&gt;, dove &lt;code&gt;Store&lt;/code&gt; &amp;egrave; il nome della nostra applicazione. Se guardiamo al file &lt;code&gt;application.rb&lt;/code&gt;, vedremo che tale nome dell&amp;rsquo;applicazione &amp;egrave; definito proprio l&amp;agrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
require File.expand_path(&amp;#x27;../boot&amp;#x27;, __FILE__)

require &amp;#x27;rails/all&amp;#x27;

# If you have a Gemfile, require the gems listed there, including any gems
# you&amp;#x27;ve limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)

module Store
  class Application &amp;lt; Rails::Application
     # Configure sensitive parameters which will be filtered from the log file.
    config.filter_parameters += [:password]
  end
end
&lt;/pre&gt;

&lt;p&gt;La classe &lt;code&gt;Store::Application&lt;/code&gt; &amp;egrave; dove molte delle configurazioni dell&amp;rsquo;applicazione avvengono e specializza da &lt;code&gt;Rails::Application&lt;/code&gt;. Ogni cosa prefissata dal namespace &lt;code&gt;Rails&lt;/code&gt; &amp;egrave; tipicamente definita nella cartella &lt;code&gt;railties&lt;/code&gt; nel codice sorgente Rails; il codice della classe per &lt;code&gt;Rails::Application&lt;/code&gt; &amp;egrave; definito in &lt;code&gt;rails/railties/lib/rails/application.rb&lt;/code&gt; e in questo file troveremo il metodo &lt;code&gt;routes&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/railties/lib/rails/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def routes
  @routes ||= ActionDispatch::Routing::RouteSet.new
end
&lt;/pre&gt;

&lt;p&gt;Questo &amp;egrave; il metodo che viene richiamato nel file di route della nostra applicazione e tutto ci&amp;ograve; che fa &amp;egrave; di creare una nuova &lt;code&gt;ActionDispatch::Routing::RouteSet&lt;/code&gt;. Il metodo route restituisce questo nuovo &lt;code&gt;RouteSet&lt;/code&gt; e nella prima riga del nostro file di route chiamiamo proprio la &lt;code&gt;draw&lt;/code&gt; su questo oggetto. Vediamo ci&amp;ograve; che fa il metodo &lt;code&gt;draw&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nel codice sorgente di Rails una classe la si pu&amp;ograve; spesso trovare in un file omonimo o dal nome analogo, infatti la classe &lt;code&gt;RouteSet&lt;/code&gt; non fa eccezione. All&amp;rsquo;interno della classe troviamo il metodo &lt;code&gt;draw&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/route_set.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def draw(&amp;amp;block)
  clear! unless @disable_clear_and_finalize

  mapper = Mapper.new(self)
  if block.arity == 1
    mapper.instance_exec(DeprecatedMapper.new(self), &amp;amp;block)
  else
    mapper.instance_exec(&amp;amp;block)
  end

   finalize! unless @disable_clear_and_finalize

   nil
end
&lt;/pre&gt;

&lt;p&gt;Il metodo &lt;code&gt;draw&lt;/code&gt; accetta un blocco per argomento. Per prima cosa ripulisce qualsiasi eventuale route gi&amp;agrave; presente, poi crea un nuovo oggetto &lt;code&gt;Mapper&lt;/code&gt;, passando ad esso &lt;code&gt;self&lt;/code&gt; (il &lt;code&gt;RouteSet&lt;/code&gt;). (Approfondiremo la classe &lt;code&gt;Mapper&lt;/code&gt; fra poco.) Dopodich&amp;egrave; il metodo controlla l&amp;rsquo;&lt;code&gt;arity&lt;/code&gt; del blocco, ossia quanti argomenti sono stati passati ad esso. Se gli &amp;egrave; stato passato un unico argomento, allora significa che il file di routing sta usando una sintassi Rails 2. Tutto ci&amp;ograve; viene fatto ovviamente per avere retrocompatibilit&amp;agrave; con le versioni precedenti a Rails 3, che passano una variabile &lt;code&gt;map&lt;/code&gt; al blocco, in questo modo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do |map|
  # Instaradamenti a la Rails 2...
end
&lt;/pre&gt;

&lt;p&gt;A prescindere poi che l&amp;rsquo;applicazione usi una sintassi di routing stile Rails 2 piuttosto che Rails 3, viene chiamata una &lt;code&gt;instance_exec&lt;/code&gt;. Nel caso di sintassi Rails 3, si passa direttamente il blocco a tale metodo, mentre invece se si tratta di sintassi Rails 2, viene creato un nuovo oggetto &lt;code&gt;DeprecatedMapper&lt;/code&gt; che viene passato come primo argomento oltre al blocco. In entrambi i casi, ci&amp;ograve; far&amp;agrave; s&amp;igrave; che il blocco sia eseguito come se fosse stato definito all&amp;rsquo;interno dell&amp;rsquo;istanza del mapper. La conseguenza di questa azione implica che tutto ci&amp;ograve; che &amp;egrave; definito all&amp;rsquo;interno del blocco nel file di route, viene invocato sull&amp;rsquo;istanza di un oggetto &lt;code&gt;Mapper&lt;/code&gt;. Questo trucco ci rende disponibile quella potente sintassi domain-specific dei file di route in Rails 3, nei quali &amp;egrave; possibile chiamare semplicemente dei metodi tipo &lt;code&gt;resources&lt;/code&gt; senza la necessit&amp;agrave; di dover esplicitamente farlo su istanze specifiche di una determinata classe, come invece si faceva in Rails 2, quando si usava la &lt;code&gt;map.resources&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;L&amp;rsquo;ultima cosa che viene fatta dal metodo draw &amp;egrave; la chiamata al &lt;code&gt;finalize!&lt;/code&gt;, che &amp;egrave; definito nella classe &lt;code&gt;RouteSet&lt;/code&gt; e che "congela" l&amp;rsquo;insieme dei route.&lt;/p&gt;

&lt;h3&gt;Come avviene il mapping di un route&lt;/h3&gt;

&lt;p&gt;Ora che sappiamo che tutto quanto si trova dentro al file di route in Rails 3 viene invocato su di un&amp;rsquo;istanza di &lt;code&gt;Mapper&lt;/code&gt;, usiamo un semplice route come esempio e vediamo come viene processato:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  match &amp;#x27;products&amp;#x27;, :to =&amp;gt; &amp;#x27;products#index&amp;#x27;
end
&lt;/pre&gt;

&lt;p&gt;Diamo un&amp;rsquo;occhiata alla classe &lt;code&gt;Mapper&lt;/code&gt; per vedere cosa fa il metodo &lt;code&gt;match&lt;/code&gt;. Ci sono molti metodi denominati &lt;code&gt;match&lt;/code&gt; all&amp;rsquo;interno di quella classe; quello che ci interessa &amp;egrave; nel module &lt;code&gt;Base&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
module Base
  def initialize(set) #:nodoc:
    @set = set
  end

  def root(options = {})
    match &amp;#x27;/&amp;#x27;, options.reverse_merge(:as =&amp;gt; :root)
  end

  def match(path, options=nil)
    mapping = Mapping.new(@set, @scope, path, options || {}).to_route
    @set.add_route(*mapping)
    self
  end

  # other methods

end
&lt;/pre&gt;

&lt;p&gt;Per creare un nuovo oggetto &lt;code&gt;Mapper&lt;/code&gt;, dobbiamo passare al costruttore un oggetto &lt;code&gt;RouteSet&lt;/code&gt;. Infatti, quando viene invocato il metodo &lt;code&gt;match&lt;/code&gt; nel file di route per creare un nuovo route, questo nuovo route viene aggiunto all&amp;rsquo;insieme passato. Tutto ci&amp;ograve; avviene mediante la creazione di un nuovo oggetto di tipo &lt;code&gt;Mapping&lt;/code&gt; e la conseguente invocazione su di esso del metodo &lt;code&gt;to_route&lt;/code&gt;. Si noti anche il metodo &lt;code&gt;root&lt;/code&gt;, che &amp;egrave; molto semplice. Tutto ci&amp;ograve; che fa &amp;egrave; chiamare &lt;code&gt;match&lt;/code&gt;, passandogli l&amp;rsquo;URL di root e aggiungendo l&amp;rsquo;opzione &lt;code&gt;:as =&amp;gt; :root&lt;/code&gt;, affinch&amp;egrave; diventi un named route. Ogni volta che si definisce nella propria applicazione Rails un URL di root, dietro le quinte viene dunque semplicemente invocato il metodo &lt;code&gt;match&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ora vediamo pi&amp;ugrave; in dettaglio la classe &lt;code&gt;Mapping&lt;/code&gt;, definita nel file &lt;code&gt;mapper.rb&lt;/code&gt;:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class Mapping #:nodoc:
  IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]

  def initialize(set, scope, path, options)
    @set, @scope = set, scope
    @options = (@scope[:options] || {}).merge(options)
    @path = normalize_path(path)
    normalize_options!
  end

  def to_route
    [ app, conditions, requirements, defaults, @options[:as], @options[:anchor] ]
  end

  private 

  def normalize_options!
    path_without_format = @path.sub(/\(\.:format\)$/, &amp;#x27;&amp;#x27;)

    if using_match_shorthand?(path_without_format, @options)
      to_shorthand    = @options[:to].blank?
      @options[:to] ||= path_without_format[1..-1].sub(%r{/([^/]*)$}, &amp;#x27;#\1&amp;#x27;)
      @options[:as] ||= Mapper.normalize_name(path_without_format)
    end

    @options.merge!(default_controller_and_action(to_shorthand))
  end

  # other private methods omitted.

end
&lt;/pre&gt;

&lt;p&gt;All&amp;rsquo;atto dell&amp;rsquo;inizializzazione del &lt;code&gt;Mapper&lt;/code&gt;, sono impostate alcune variabili di istanza in base ai parametri passati, dopodich&amp;egrave; viene invocato il &lt;code&gt;normalize_options!&lt;/code&gt;. Il metodo &lt;code&gt;normalize_options!&lt;/code&gt; esegue un controllo per vedere se si sta utilizzando un determinato tipo di sintassi "abbreviata" nel file di route e nel metodo &lt;code&gt;using_match_shorthand?&lt;/code&gt; che viene chiamato, osserviamo un interessante escamotage. Esiste un modo rapido per definire le action di un controller in cui si separa il controller e i nomi delle action con uno slash:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
# match &amp;quot;account/overview&amp;quot;
def using_match_shorthand?(path, options)
  path &amp;amp;&amp;amp; options.except(:via, :anchor, :to, :as).empty? &amp;amp;&amp;amp; path =~ %r{^/[\w\/]+$}
end
&lt;/pre&gt;

&lt;p&gt;Se abbiamo definito il nostro route in questo modo, allora le opzioni &lt;code&gt;:to&lt;/code&gt; e &lt;code&gt;:as&lt;/code&gt; saranno impostate per noi, a seconda del nome dell&amp;rsquo;URL. Verifichiamolo tornando al file di route della nostra applicazione, aggiungendo un altro route che utilizzi la sintassi smart:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
Store::Application.routes.draw do
  match &amp;#x27;products&amp;#x27;, :to =&amp;gt; &amp;#x27;products#index&amp;#x27;
  match &amp;#x27;products/recent&amp;#x27;, :to =&amp;gt; &amp;#x27;products#recent&amp;#x27;
end
&lt;/pre&gt;

&lt;p&gt;Abbiamo fornito un parametro &lt;code&gt;:to&lt;/code&gt; a questo nuovo route, ma verrebbe comunque aggiunto automaticamente se non lo avessimo specificato. Il metodo di shortcut crea automaticamente per noi anche un parametro &lt;code&gt;:as&lt;/code&gt;, come se avessimo aggiunto &lt;code&gt;:as =&amp;gt; :products_recent&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Come viene usato Rack nel routing&lt;/h3&gt;

&lt;p&gt;Tornando al metodo &lt;code&gt;match&lt;/code&gt;, una volta creato un nuovo oggetto &lt;code&gt;Mapping&lt;/code&gt;, richiamiamo il metodo &lt;code&gt;to_route&lt;/code&gt; su di esso. Questo metodo restituisce un array di opzioni che sono usate per creare un nuovo route:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def to_route
  [ app, conditions, requirements, defaults, @options[:as], @options[:anchor] ]
end
&lt;/pre&gt;

&lt;p&gt;I primi quattro elementi nell&amp;rsquo;array di sopra sono i valori restituiti dalle chiamate ai metodi presenti nella classe &lt;code&gt;Mapper&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def app
  Constraints.new(
    to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults =&amp;gt; defaults),
    blocks,
    @set.request_class
  )
end

def conditions
  { :path_info =&amp;gt; @path }.merge(constraints).merge(request_method_condition)
end

def requirements
  @requirements ||= (@options[:constraints].is_a?(Hash) ? @options[:constraints] : {}).tap do |requirements|
    requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
    @options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
   end
end

def defaults
  @defaults ||= (@options[:defaults] || {}).tap do |defaults|
    defaults.reverse_merge!(@scope[:defaults]) if @scope[:defaults]
    @options.each { |k, v| defaults[k] = v unless v.is_a?(Regexp) || IGNORE_OPTIONS.include?(k.to_sym) }
  end
end
&lt;/pre&gt;

&lt;p&gt;La prima opzione &amp;egrave; &lt;code&gt;app&lt;/code&gt;; ogniqualvolta vediate un qualcosa chiamato &lt;code&gt;app&lt;/code&gt; nel codice sorgente di Rails, &amp;egrave; molto probabile che si faccia riferimento a un&amp;rsquo;applicazione Rack. Questo metodo &lt;code&gt;app&lt;/code&gt; restituisce un nuovo oggetto &lt;code&gt;Constraints&lt;/code&gt;, per cui vediamo se si tratta effettivamente, in questo caso, di un&amp;rsquo;applicazione Rack.&lt;/p&gt;

&lt;p&gt;La classe &lt;code&gt;Constraints&lt;/code&gt; &amp;egrave; definita nello stesso file &lt;code&gt;mapper.rb&lt;/code&gt;. Accetta una serie di metodi, uno dei quali &amp;egrave; chiamato &lt;code&gt;call&lt;/code&gt; e prende in ingresso come parametro un environment:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def call(env)
  req = @request.new(env)

  @constraints.each { |constraint|
    if constraint.respond_to?(:matches?) &amp;amp;&amp;amp; !constraint.matches?(req)
      return [ 404, {&amp;#x27;X-Cascade&amp;#x27; =&amp;gt; &amp;#x27;pass&amp;#x27;}, [] ]
    elsif constraint.respond_to?(:call) &amp;amp;&amp;amp; !constraint.call(*constraint_args(constraint, req))
      return [ 404, {&amp;#x27;X-Cascade&amp;#x27; =&amp;gt; &amp;#x27;pass&amp;#x27;}, [] ]
    end
  }

  @app.call(env)
end
&lt;/pre&gt;

&lt;p&gt;La classe &lt;code&gt;Constraints&lt;/code&gt; sembra proprio un&amp;rsquo;applicazione Rack. Una cosa interessante sulla classe &lt;code&gt;Constraints&lt;/code&gt;  &amp;egrave; che fa l&amp;rsquo;override del metodo &lt;code&gt;self.new&lt;/code&gt;. Potreste domandarvi il perch&amp;egrave;, dal momento che esiste gi&amp;agrave; anche un metodo &lt;code&gt;initialize&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def self.new(app, constraints, request = Rack::Request)
  if constraints.any?
    super(app, constraints, request)
  else
    app
  end
end

attr_reader :app

def initialize(app, constraints, request)
  @app, @constraints, @request = app, constraints, request
end
&lt;/pre&gt;

&lt;p&gt;La ragione dietro a questa scelta &amp;egrave; solo di performance. &lt;code&gt;Constraints&lt;/code&gt; &amp;egrave; un pezzo del middleware di Rack; in altri termini, racchiude un&amp;rsquo;altra applicazione Rack. Il primo argomento passato al &lt;code&gt;self.new&lt;/code&gt; &amp;egrave; &lt;code&gt;app&lt;/code&gt;, che rappresenta un&amp;rsquo;applicazione Rack; quando viene invocato il metodo &lt;code&gt;call&lt;/code&gt;, se viene scatenato uno dei constraints, restituisce un errore &lt;code&gt;404&lt;/code&gt;, altrimenti scatener&amp;agrave; l&amp;rsquo;applicazione Rack che sta wrappando. Il metodo &lt;code&gt;self.new&lt;/code&gt; fa parte di logiche di ottimizzazione di performance e serve affinch&amp;egrave;, quando viene chiamato, Rails non allochi un altro oggetto in memoria, wrappandolo e usandolo, ma piuttosto restituisca semplicemente l&amp;rsquo;applicazione Rack iniziale stessa.&lt;/p&gt;

&lt;p&gt;Torniamo ora al codice che richiama tutto ci&amp;ograve;. Si noti che i primi due argomenti sono una applicazione Rack e un array di vincoli. Il tutto viene richiamato nel metodo &lt;code&gt;app&lt;/code&gt; della classe &lt;code&gt;Mapping&lt;/code&gt;. Quando qui si crea un nuovo vincolo, controlliamo per vedere se il metodo to risponde al &lt;code&gt;call&lt;/code&gt;. (Il metodo &lt;code&gt;to&lt;/code&gt; restituisce semplicemente l&amp;rsquo;opzione &lt;code&gt;:to&lt;/code&gt; che era stata definita per il route.) In caso affermativo, si tratta di un&amp;rsquo;applicazione Rack e viene passata questa; altrimenti si passa un nuovo oggetto &lt;code&gt;RouteSet::Dispatcher&lt;/code&gt; con un paio di opzioni di default:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/mapper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def app
  Constraints.new(
    to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults =&amp;gt; defaults),
    blocks,
    @set.request_class
  )
end
&lt;/pre&gt;

&lt;p&gt;E&amp;rsquo; questo codice a darci la possibilit&amp;agrave; di passare un&amp;rsquo;applicazione Rack ad un route in questa maniera:&lt;/p&gt;

&lt;pre class="ruby"&gt;
&amp;nbsp;&amp;nbsp;root&amp;nbsp;:to&amp;nbsp;=&amp;gt;&amp;nbsp;proc&amp;nbsp;{&amp;nbsp;|env|&amp;nbsp;[200,&amp;nbsp;{},&amp;nbsp;[&amp;quot;Welcome&amp;quot;]]&amp;nbsp;}
&lt;/pre&gt;

&lt;p&gt;Ci sono pi&amp;ugrave; approfondimenti sull&amp;rsquo;uso di Rack nei route nell&amp;rsquo;episodio 222 [&lt;a href="http://railscasts.com/episodes/222-rack-in-rails-3"&gt;guardalo&lt;/a&gt;, &lt;a href="http://it.asciicasts.com/episodes/222-rack-in-rails-3"&gt;leggilo&lt;/a&gt;]. Poterlo usare nei route ci da molta flessibilit&amp;agrave;.&lt;/p&gt;

&lt;p&gt;Se non passiamo un&amp;rsquo;applicazione Rack all&amp;rsquo;opzione &lt;code&gt;:to&lt;/code&gt;, allora viene creato un nuovo oggetto &lt;code&gt;RouteSet::Dispatcher&lt;/code&gt;. Vediamo ora come viene gestito quest&amp;rsquo;ultimo.&lt;/p&gt;

&lt;p&gt;La classe &lt;code&gt;Dispatcher&lt;/code&gt; gestisce lo smistamento di una richiesta al controller corretto che dovr&amp;agrave; servirla. Nel suo metodo &lt;code&gt;controller_reference&lt;/code&gt; si pu&amp;ograve; vedere il codice dove viene identificato l&amp;rsquo;opportuno controller:&lt;/p&gt; 
 
&lt;p class="codeFilePath"&gt;rails/actionpack/lib/action_dispatch/routing/route_set.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def controller_reference(controller_param)
  unless controller = @controllers[controller_param]
    controller_name = &amp;quot;#{controller_param.camelize}Controller&amp;quot;
    controller = @controllers[controller_param] =
       ActiveSupport::Dependencies.ref(controller_name)
  end
  controller.get
end
&lt;/pre&gt;

&lt;p&gt;Questa classe ha anche dei metodi per fare cose tipo impostare l&amp;rsquo;action di default a &lt;code&gt;index&lt;/code&gt; se non ne &amp;egrave; stata definita una e un metodo &lt;code&gt;dispatch&lt;/code&gt; che chiama la action stessa e che restituisce un&amp;rsquo;applicazione Rack. Tutto ci&amp;ograve; significa che possiamo prendere uno qualsiasi dei nostri controller, chiamare &lt;code&gt;action&lt;/code&gt; su di esso, passandogli il nome della action e ottenendo un&amp;rsquo;applicazione Rack in risposta:&lt;/p&gt;

&lt;pre class="terminal"&gt;
ruby-1.9.2-p0 &amp;gt; ProductsController.action(&amp;quot;index&amp;quot;)
 =&amp;gt; #&amp;lt;Proc:0x00000100ec56c0@/Users/asalicetti/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_controller/metal.rb:172&amp;gt;
&lt;/pre&gt; 

&lt;p&gt;Questo &amp;egrave; quel che succede dietro le quinte quando passiamo un file di route tipo questo:&lt;/p&gt;

&lt;pre class="ruby"&gt;
match &amp;#x27;products&amp;#x27;, :to =&amp;gt; &amp;#x27;products#index&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;La stringa &lt;code&gt;products#index&lt;/code&gt; &amp;egrave; convertita in &lt;code&gt;ProductsController.action(&amp;quot;index&amp;quot;)&lt;/code&gt; e questa restituisce un&amp;rsquo;applicazione Rack. La sintassi della stringa &amp;egrave; una banale scorciatoia per fare la stessa cosa.&lt;/p&gt;

&lt;p&gt;C&amp;rsquo;&amp;egrave; molto altro in merito al routing che potremmo dire in questo episodio, ma questo sembra anche un buon momento per fermarsi. Ci sono i metodi &lt;code&gt;resources&lt;/code&gt; che generano una serie di route, ci sono i vari metodi che permettono di limitare le condizioni a determinati scope e passare blocchi a queste affinch&amp;egrave; sia possibile realizzare un cascade di scope, ma in effetti fin qui c&amp;rsquo;&amp;egrave; abbastanza per incoraggiarvi ad esplorare per conto vostro il codice di routing.&lt;/p&gt;

&lt;p&gt;Il routing &amp;egrave; una delle aree pi&amp;ugrave; complicata di Rails, per cui se siete un po&amp;rsquo; intimoriti dalla complessit&amp;agrave; del codice che vi troverete di fronte, non vi preoccupate: &amp;egrave; davvero complesso. Partite con alcune altre parti del codice di Rails prima e fateci il callo prima di affrontare parti pi&amp;ugrave; complesse.&lt;/p&gt;</description>
      <pubDate>Tue, 05 Oct 2010 20:08:14 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/231-esploriamo-il-routing-di-rails-3</guid>
      <link>http://it.asciicasts.com/episodes/231-esploriamo-il-routing-di-rails-3</link>
    </item>
    <item>
      <title>Risorse ereditate</title>
      <description>&lt;p&gt;In questo episodio daremo un&amp;rsquo;occhiata al gem di Jos&amp;eacute; Valim chiamato &lt;a href="http://github.com/josevalim/inherited_resources"&gt;Inherited Resources&lt;/a&gt;. Questo gem estrae funzionalit&amp;agrave; comuni dai controller RESTful e ci permette in tal modo di rimovere alcune duplicazioni dal codice dei nostri controller. Non si tratta del primo gem Rails a fornire questo genere di funzionalit&amp;agrave;: nell&amp;rsquo;&lt;a href="http://railscasts.com/episodes/92-make-resourceful"&gt;episodio 92&lt;/a&gt; abbiamo parlato di un gem chiamato make_resourceful analogo e esistono anche diversi plugin che fanno la stessa cosa. Ciascuno segue un approccio lievemente diverso, per cui, al solito, vale la pena cofrontarli fra loro prima di decidere quale usare. Noi abbiamo scelto Inherited Resources dal momento che funziona bene con Rails 3.0 e sembra anche quello pi&amp;ugrave; aggiornato.&lt;/p&gt;

&lt;p&gt;L&amp;rsquo;applicazione Rails con cui lavoreremo in questo episodio sar&amp;agrave; una semplice applicazione di e-commerce. Questa applicazione ha un elenco di prodotti e ciascuno di essi ha una serie di recensioni ad esso associate:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/461/original/E230I01.png" width="816" height="409" alt="La pagina di elenco prodotti."/&gt;
&lt;/div&gt;

&lt;p&gt;Usereme Inherited Resources per ripulire un po&amp;rsquo; il codice di questa applicazione e vedere quanto codice dei controller potremo rimuovere senza intaccare le funzionalit&amp;agrave; applicative.&lt;/p&gt;

&lt;h3&gt;Installazione di Inherited Resources&lt;/h3&gt;

&lt;p&gt;Il codice del &lt;code&gt;ProductController&lt;/code&gt; attualmente appare cos&amp;igrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/products_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ProductsController &amp;lt; ApplicationController
  def index
    @products = Product.all
  end

  def show
    @product = Product.find(params[:id])
  end

  def new
    @product = Product.new
  end
  
  def create
    @product = Product.new(params[:product])
    if @product.save
      flash[:notice] = &amp;quot;Successfully created product.&amp;quot;
      redirect_to @product
    else
      render :action =&amp;gt; &amp;#x27;new&amp;#x27;
    end
  end
  
  def edit
    @product = Product.find(params[:id])
  end
  
  def update
    @product = Product.find(params[:id])
    if @product.update_attributes(params[:product])
      flash[:notice] = &amp;quot;Successfully updated product.&amp;quot;
      redirect_to @product
    else
      render :action =&amp;gt; &amp;#x27;edit&amp;#x27;
    end
  end
  
  def destroy
    @product = Product.find(params[:id])
    @product.destroy
    flash[:notice] = &amp;quot;Successfully destroyed product.&amp;quot;
    redirect_to products_url
  end

end
&lt;/pre&gt;

&lt;p&gt;Se avete diversi controller RESTful nella vostra applicazione, vi troverete a scrivere del codice tipo questo in ciascuno di essi ed &amp;egrave; proprio in situazioni del genere che Inherited Resources si rivela molto utile. Se, tuttavia, in generale tendete a rendere molto personalizzate le logiche dei controller, allora un&amp;rsquo;astrazione come quella proposta da Inherited Resources potebbe non fare al caso vostro. Il controller riportato di sopra aderisce al pattern RESTful abbastanza bene, per cui possiamo usarlo per vedere ci&amp;ograve; che &amp;egrave; offerto dal gem Inherited Resources.&lt;/p&gt;

La nostra applicazione di e-commerce &amp;egrave; scritta in Rails 3, per cui aggiungiamo Inherited Resources ad essa, includendo il gem nel nostro &lt;code&gt;Gemfile&lt;/code&gt;:

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;
source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.0&amp;#x27;

gem &amp;#x27;sqlite3-ruby&amp;#x27;, :require =&amp;gt; &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;inherited_resources&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;Lo si installa al solito modo con:&lt;/p&gt;
&lt;pre class="terminal"&gt;
$ bundle install
&lt;/pre&gt;

&lt;p&gt;Ci&amp;ograve;, come sempre, causer&amp;agrave; l&amp;rsquo;installazione del gem e di un paio di dipendenze: &lt;code&gt;has_scope&lt;/code&gt; e &lt;code&gt;responders&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Una volta installati i gem, si pu&amp;ograve; aggiornare il nostro &lt;code&gt;ProductsController&lt;/code&gt; per fargli usare le Inherited Resources. Per farlo, renderemo il controller specializzazione di &lt;code&gt;InheritedResources::Base&lt;/code&gt; anzich&amp;egrave; di &lt;code&gt;ApplicationController&lt;/code&gt;. &lt;code&gt;InheritedResources::Base&lt;/code&gt; specializza &lt;code&gt;ApplicationController&lt;/code&gt;, per cui esporr&amp;agrave; anche tutte le funzionalit&amp;agrave; del padre.&lt;/p&gt; 

&lt;p&gt;Poich&amp;egrave; il &lt;code&gt;ProductsController&lt;/code&gt; &amp;egrave; un controller RESTful abbastanza standard, possiamo sostituire tutti i suoi metodi con il codice ereditato da Inherited Resources, riducendo cos&amp;igrave; il codice:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/products_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ProductsController &amp;lt; InheritedResources::Base

end
&lt;/pre&gt;

&lt;p&gt;Dobbiamo riavviare il server per fare in modo che i nuovi gem vengano ricaricati, ma una volta fatto, vedremo che le pagine relative ai prodotti funzionano esattamente come prima. Possiamo persino creare un nuovo prodotto con successo e avere anche il messaggio flash di conferma:&lt;/p&gt;
 
&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/462/original/E230I02.png" width="816" height="409" alt="L&amp;rsquo;aggiunta di un nuovo prodotto."/&gt;
&lt;/div&gt;

&lt;h3&gt;Personalizzare una action&lt;/h3&gt;

&lt;p&gt;Quando abbiamo creato un nuovo prodotto, prima, siamo stati ridiretti alla pagina di dettaglio (&lt;code&gt;show&lt;/code&gt;) dello stesso al termine dell&amp;rsquo;operazione, ma come potremmo fare per far s&amp;igrave; che l&amp;rsquo;applicazione ci mandi piuttosto alla action &lt;code&gt;index&lt;/code&gt;? Inherited Resources ci permette di ridefinire una qualunque delle proprie action di default, semplicemente ridefinando il metodo opportuno nel controller, per cui potremmo scrivere un metodo &lt;code&gt;create&lt;/code&gt; nel &lt;code&gt;ProductsController&lt;/code&gt; che crei il nuovo prodotto e che rimandi alla action &lt;code&gt;index&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Non c&amp;rsquo;&amp;egrave; bisogno, tuttavia, di riscrivere completamente la action create solo per modificare il redirect. Possiamo includere il comportamento di Inherited Resource chiamando il metodo &lt;code&gt;create!&lt;/code&gt; e passandogli un blocco. Il cambio dell&amp;rsquo;URL di redirect alla creazione di un nuovo oggetto di modello &amp;egrave; un&amp;rsquo;operazione piuttosto comune che si vorrebbe poter fare, per cui possiamo semplicemente restituire l&amp;rsquo;URL desiderato nel blocco:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/products_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ProductsController &amp;lt; InheritedResources::Base
  def create
    create! { products_path }
  end
end
&lt;/pre&gt;

&lt;p&gt;Ci sono altre cose che potremmo fare nel blocco e sono tutte spiegate nella &lt;a href="http://github.com/josevalim/inherited_resources#readme"&gt;documentazione&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ora, creando un nuovo prodotto, siamo ridiretti alla action &lt;code&gt;index&lt;/code&gt; proprio come volevamo:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/463/original/E230I03.png" width="816" height="409" alt="L&amp;rsquo;aggiunta di un prodotto ora ci porta alla action index."/&gt;
&lt;/div&gt;

&lt;h3&gt;Lavorare con formati differenti&lt;/h3&gt;

&lt;p&gt;Se vogliamo che il controller sia in grado di rispondere in diversi formati, tipo XML e HTML, &amp;egrave; semplice. Basta aggiungere la &lt;code&gt;respond_to&lt;/code&gt; proprio come faremmo in un normale controller Rails 3:&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/app/controllers/products_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ProductsController &amp;lt; InheritedResources::Base
  respond_to :html, :xml

  def create
    create! { products_path }
  end
end
&lt;/pre&gt;

&lt;p&gt;Ci&amp;ograve; funzioner&amp;agrave; allo stesso modo mostrato nell&amp;rsquo;episodio 224 [&lt;a href="http://railscasts.com/episodes/224-controllers-in-rails-3"&gt;guardalo&lt;/a&gt;, &lt;a href="http://it.asciicasts.com/episodes/224-controller-in-rails-3"&gt;leggilo&lt;/a&gt;]. Se ora visitiamo &lt;code&gt;/products.xml&lt;/code&gt; otterremo una lista di prodotti in XML:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/464/original/E230I04.png" width="819" height="408" alt="I prodotti in formato XML."/&gt;
&lt;/div&gt;

&lt;h3&gt;Nested Resource&lt;/h3&gt;

&lt;p&gt;Ora che abbiamo ripulito il &lt;code&gt;ProductsController&lt;/code&gt;, spostiamo l&amp;rsquo;attenzione sul &lt;code&gt;ReviewsController&lt;/code&gt;. Le opinioni sono annidate sotto i prodotti, per cui la review di un articolo sar&amp;agrave; all&amp;rsquo;URL &lt;code&gt;/products/1/reviews&lt;/code&gt; per il prodotto di &lt;code&gt;id&lt;/code&gt; pari a &lt;code&gt;1&lt;/code&gt;. Questo per quel che riguarda la action &lt;code&gt;index&lt;/code&gt; del &lt;code&gt;ReviewsController&lt;/code&gt;. Analogamente, se aggiungiamo una opinione, l&amp;rsquo;URL sar&amp;agrave; sempre innestato sotto i prodotti:&lt;/p&gt;
 
&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/465/original/E230I05.png" width="800" height="406" alt="Le opinioni sono innestate sotto i prodotti."/&gt;
&lt;/div&gt;

&lt;p&gt;Il codice per il &lt;code&gt;ReviewsController&lt;/code&gt; appare cos&amp;igrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/reviews_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ReviewsController &amp;lt; ApplicationController
  def index
    @product = Product.find(params[:product_id])
    @reviews = @product.reviews
  end

  def new
    @product = Product.find(params[:product_id])
    @review = Review.new
  end
  
  def create
    @product = Product.find(params[:product_id])
    @review = @product.reviews.build(params[:review])
    if @review.save
      flash[:notice] = &amp;quot;Successfully created review.&amp;quot;
      redirect_to product_reviews_path(@product)
    else
      render :action =&amp;gt; &amp;#x27;new&amp;#x27;
    end
  end

end
&lt;/pre&gt;

&lt;p&gt;La differenza pi&amp;ugrave; evidente fra questo controller e il &lt;code&gt;ProductsController&lt;/code&gt; &amp;egrave; che il primo ha solo tre delle sette action RESTful. L&amp;rsquo;altra differenza &amp;egrave; che, siccome gestisce l&amp;rsquo;innestamento, ciascuna action ottiene il prodotto di riferimento basandosi su un parametro nell&amp;rsquo;URL.&lt;/p&gt;

&lt;p&gt;Anche se in questo contesto si tratta di una risorsa innestata, il comportamento &amp;egrave; fondamentalmente lo stesso che quello nel &lt;code&gt;ProductsController&lt;/code&gt; e le Inherited Resources funzioneranno bene anche qui. Possiamo rimuovere il codice esistente nel controller e cambiare la tassonomia della classe, affinch&amp;egrave; erediti da &lt;code&gt;InheritedResources::Base&lt;/code&gt;. Tutto quello che dobbiamo fare per gestire l&amp;rsquo;innestamento &amp;egrave; di aggiungere &lt;code&gt;belongs_to&lt;/code&gt;, che &amp;egrave; un metodo fornito da Inherited Resources e che pu&amp;ograve; essere usato nella definizione di relazioni fra controller allo stesso modo in cui lo si fa fra modelli. Sistemato tutto ci&amp;ograve;, Inherited Resources gestisce il recupero del prodotto corretto al posto nostro:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/reviews_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ReviewsController &amp;lt; InheritedResources::Base
  belongs_to :product
end
&lt;/pre&gt;

&lt;p&gt;Per come &amp;egrave; ora, il &lt;code&gt;ReviewsController&lt;/code&gt; esporr&amp;agrave; tutte e sette le action di default, dal momento che questo &amp;egrave; il comportamento di default di Inherited Resources, ma noi vogliamo che questo controller si limiti a rispondere solamente a &lt;code&gt;index&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt; e &lt;code&gt;create&lt;/code&gt;. Possiamo usare il metodo &lt;code&gt;actions&lt;/code&gt; per limitare le action disponibili:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/reviews_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ReviewsController &amp;lt; InheritedResources::Base
  belongs_to :product
  actions :index, :new, :create
end
&lt;/pre&gt;

&lt;p&gt;Come fatto gi&amp;agrave; per il &lt;code&gt;ProductsController&lt;/code&gt;, vogliamo anche cambiare l&amp;rsquo;URL a cui rimandiamo a seguito della creazione di una nuova opinione. Ci sono molti metodi helper per gli URL forniti da Inherited Resources per ridirigere a varie action, che tornano utili in questo caso in cui abbiamo un innestamento. In questo caso possiamo usare un metodo chiamato &lt;code&gt;collection_url&lt;/code&gt; che ridirige alla action &lt;code&gt;index&lt;/code&gt; e gestisce l&amp;rsquo;innestamento per noi:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/reviews_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ReviewsController &amp;lt; InheritedResources::Base
  belongs_to :product
  actions :index, :new, :create
  
  def create
    create! { collection_url }
  end
end
&lt;/pre&gt;

&lt;p&gt;Possiamo testare il tutto aggiungendo una opinione:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/466/original/E230I06.png" width="801" height="451" alt="Aggiunta di una opinione."/&gt;
&lt;/div&gt;

&lt;p&gt;Dopo che abbiamo fatto il submit della nuova opinione verremo ridiretti alla pagina delle opinioni per tale prodotto proprio come volevamo:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/467/original/E230I07.png" width="801" height="526" alt="Dopo aver aggiunto un&amp;rsquo;opinone veniamo ora ridiretti nuovamente alla pagina delle opinioni."/&gt;
&lt;/div&gt;

&lt;h3&gt;Scope pubblici&lt;/h3&gt;

&lt;p&gt;Inherited Resources ha un&amp;rsquo;altra utile funzionalit&amp;agrave; chiamata &lt;code&gt;has_scope&lt;/code&gt;. Per usarla, dobbiamo solo aggiungere un riferimento al gem nel &lt;code&gt;Gemfile&lt;/code&gt; e poi rilanciare &lt;code&gt;bundle install&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;
source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.0&amp;#x27;

gem &amp;#x27;sqlite3-ruby&amp;#x27;, :require =&amp;gt; &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;inherited_resources&amp;#x27;
gem &amp;#x27;has_scope&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;Installato il tutto, possiamo chiamare &lt;code&gt;has_scope&lt;/code&gt; in qualsiasi dei nostri controller passandogli il nome di uno scope presente sul modello associato. Per questo esempio, aggiungeremo lo scope &lt;code&gt;limit&lt;/code&gt;, che &amp;egrave; fornito per default a tutti i modelli in Rails 3, al &lt;code&gt;ProductsController&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/products_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ProductsController &amp;lt; InheritedResources::Base
  respond_to :html, :xml
  
  has_scope :limit

  def create
    create! { products_path }
  end
end
&lt;/pre&gt;

&lt;p&gt;Con questo codice, possiamo aggiungere scope come parametri all&amp;rsquo;URL, per cui se passiamo un parametro &lt;code&gt;limit&lt;/code&gt;, verr&amp;agrave; chiamato tale scope e ridurremo il numero di prodotti mostrati:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/468/original/E230I08.png" width="800" height="358" alt="L&amp;rsquo;utilizzo dello scope limit nella stringa di query."/&gt;
&lt;/div&gt;

&lt;p&gt;Se volessimo applicare lo scope per tutte le query su quel controller, implicitamente, senza che sia necessario aggiungerlo come parametro alla stringa di query, potremmo dichiararlo con l&amp;rsquo;opzione &lt;code&gt;default&lt;/code&gt; e un valore per il parametro:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/products_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ProductsController &amp;lt; InheritedResources::Base
  respond_to :html, :xml
  
  has_scope :limit, :default =&amp;gt; 3

  def create
    create! { products_path }
  end
end
&lt;/pre&gt;

&lt;p&gt;Ora, se non passiamo un parametro &lt;code&gt;limit&lt;/code&gt; verr&amp;agrave; usato il valore di default e, in questo caso, vedremo solo tre prodotti:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/469/original/E230I09.png" width="800" height="405" alt="Viene usato il valore di default quando non si passa il parametro limit."/&gt;
&lt;/div&gt;

&lt;p&gt;Tutto ci&amp;ograve; funziona naturalemente anche con gli scope personalizzati. Aggiungeremo uno scope al modello &lt;code&gt;Review&lt;/code&gt; che ci permetter&amp;agrave; di filtrare le opinioni in base al loro punteggio:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/review.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class Review &amp;lt; ActiveRecord::Base
  belongs_to :product
  scope :rating, proc { |rating| where(:rating =&amp;gt; rating) }
end
&lt;/pre&gt;

&lt;p&gt;Ora rendiamo lo scope pubblico, aggiungendolo al &lt;code&gt;ReviewsController&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/reviews_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ReviewsController &amp;lt; InheritedResources::Base
  belongs_to :product
  actions :index, :new, :create
  has_scope :rating
  
  def create
    create! { collection_url }
  end
end
&lt;/pre&gt;

&lt;p&gt;Possiamo ora usare un parametro rating nell&amp;rsquo;URL, per limitare le opinioni in base al loro punteggio.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/470/original/E230I10.png" width="800" height="334" alt="Filtraggio delle opinioni in base al punteggio."/&gt;
&lt;/div&gt;

&lt;p&gt;Il gem &lt;code&gt;has_scope&lt;/code&gt; pu&amp;ograve; essere utilizzato al di fuori di Inherited Resources usando il metodo &lt;code&gt;apply_scopes&lt;/code&gt; all&amp;rsquo;interno della action &lt;code&gt;index&lt;/code&gt;. Ci sono ulteriori dettagli su tutto ci&amp;ograve; nella &lt;a href="http://github.com/plataformatec/has_scope"&gt;documentazione su Github&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Personalizzare il messaggio flash&lt;/h3&gt;

&lt;p&gt;L&amp;rsquo;ultima cosa che tratteremo sar&amp;agrave; come personalizzare il messaggio flash. Quando creiamo una nuova opinione, il messaggio di default &amp;egrave; &amp;ldquo;Review was successfully created.&amp;rdquo;, ma noi vorremo modificarlo affinch&amp;egrave; sia qualsiasi cosa che vogliamo, cambiando il file di internazionalizzazione. Anche se la vostra applicazione non supporta linguaggi multipli, questi file sono il posto migliore dove mettere le stringhe che verranno mostrate sull&amp;rsquo;interfaccia utente. Ogni applicazione Rails 3 ha un file di localizzazione inglese incluso al suo interno, sotto &lt;code&gt;/config/locales/en.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Per ridefinire il messaggio flash di default di Inherited Resources, creiamo una chiave &lt;code&gt;flash:&lt;/code&gt;, sotto la quale avremo una chiave contenente il nome del controller, in questo caso &lt;code&gt;reviews:&lt;/code&gt;. Sotto di essa, aggiungiamo una chiave per la action e sotto quest&amp;rsquo;ultima, una per il nome del messaggio di flash. Per il nostro controller delle opinioni, il file di configurazione apparir&amp;agrave; cos&amp;igrave;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/locales/en.yml&lt;/p&gt;
&lt;pre class="ruby"&gt;
# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.

en:
  flash:
    reviews:
      create:
        notice: &amp;quot;Your review has been created!&amp;quot;
&lt;/pre&gt;

&lt;p&gt;Se non vogliamo dover configurare tutto ci&amp;ograve; per ogni controller della nostra applicazione, possiamo sostituire il nome del controller con &lt;code&gt;actions:&lt;/code&gt; e di conseguenza i messaggi saranno applicati a tutti i singoli controller. Possiamo usare una variabile &lt;code&gt;resource_name&lt;/code&gt; a mo&amp;rsquo; di placeholder, per attualizzare il nome del modello corrente.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/locales/en.yml&lt;/p&gt;
&lt;pre class="ruby"&gt;
# Sample localization file for English. Add more files in this directory for other locales.
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.

en:
  flash:
    actions:
      create:
        notice: &amp;quot;Your {{resource_name}} has been created!&amp;quot;
&lt;/pre&gt;

&lt;p&gt;Possiamo provare il tutto, creando una nuova opinione.. Al submit, verr&amp;agrave; mostrato il messaggio flash cos&amp;igrave; personalizzato:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/471/original/E230I11.png" width="815" height="334" alt="Viene mostrato il messaggio flash personalizzato quando si crea una opinione."/&gt;
&lt;/div&gt;

&lt;p&gt;E&amp;rsquo; tutto per questo episodio. Se vi trovate a creare sempre lo stesso codice per i controller, vale la pena dare un&amp;rsquo;occhiata a Inherited Resources. Il &lt;a href="http://github.com/josevalim/inherited_resources#readme"&gt;file README&lt;/a&gt; &amp;egrave; piuttosto esaustivo e tratta anche di parti che non abbiamo menzionato in questo episodio. Vale anche la pena consultare la &lt;a href="http://wiki.github.com/josevalim/inherited_resources/"&gt;wiki page&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Mon, 20 Sep 2010 09:14:58 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/230-risorse-ereditate</guid>
      <link>http://it.asciicasts.com/episodes/230-risorse-ereditate</link>
    </item>
    <item>
      <title>Fare polling per verificare modifiche</title>
      <description>&lt;p&gt;Si immagini di avere un&amp;rsquo;applicazione di blogging che consenta ai suoi utenti di aggiungere commenti agli articoli. Il blog &amp;egrave; molto popolare, per cui vengono aggiunti nuovi commenti abbastanza di frequente. Se qualcuno arriva sul sito per leggere un articolo e i suoi commenti e poi decide di aggiungere il proprio commento, &amp;egrave; possibile che nel momento che intercorre fra il suo arrivo sul sito e il suo commento, altri nuovi commenti siano nel frattempo stati aggiunti all&amp;rsquo;articolo, rendendo potenzialmente il commento che quell&amp;rsquo;utente voleva inserire scorretto o irrilevante. Perci&amp;ograve; sarebbe utile che la pagina dell&amp;rsquo;articolo si mantenesse aggiornata automaticamente, aggiungendo, sempre in automatico, tutti i nuovi commenti aggiunti a seguito dell&amp;rsquo;ultimo caricamento della pagina. Vi mostreremo come farlo in questo episodio.&lt;/p&gt;

&lt;h3&gt;Configurazione di jQuery&lt;/h3&gt;

&lt;p&gt;Dovremo usare del JavaScript per aggiornare la pagina al volo ed in particolare useremo jQuery al posto di Prototype come nostra libreria JavaScript preferita. Dal momento che la nostra applicazione &amp;egrave; scritta in Rails 3, possiamo utilizzare il gem &lt;code&gt;&lt;a href="http://github.com/indirect/jquery-rails"&gt;jquery-rails&lt;/a&gt;&lt;/code&gt; per rendere semplice la sostituzione dei file di Prototype con quelli di jQuery.&lt;/p&gt;

&lt;p&gt;Per usare il gem, dobbiamo semplicemente aggiungere un riferimento ad esso nel &lt;code&gt;Gemfile&lt;/code&gt; della nostra applicazione:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;
gem &amp;#x27;jquery-rails&amp;#x27;
&lt;/pre&gt;

&lt;p&gt;Poi possiamo fare in modo che il tutto sia scaricato e installato lanciando:&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ bundle install
&lt;/pre&gt;

&lt;p&gt;Dopo che Bundler avr&amp;agrave; finito il suo lavoro, sar&amp;agrave; disponibile un nuovo generatore che potremo lanciare per configurare jQuery nella nostra applicazione. Quando lo lanciamo, questi rimuover&amp;agrave; i file di Prototype, aggiunger&amp;agrave; quelli di jQuery e infine sovrascriver&amp;agrave; il file di default &lt;code&gt;rails.js&lt;/code&gt; della nostra applicazione con una versione dello stesso compatibile con jQuery (se volete installare la libreria UI di jQuery insieme a jQuery, potete passare l&amp;rsquo;opzione &lt;code&gt;--ui&lt;/code&gt; al generatore):&lt;/p&gt;

&lt;pre class="terminal"&gt;
$ rails g jquery:install
      &lt;span class="passed"&gt;remove&lt;/span&gt;  public/javascripts/controls.js
      &lt;span class="passed"&gt;remove&lt;/span&gt;  public/javascripts/dragdrop.js
      &lt;span class="passed"&gt;remove&lt;/span&gt;  public/javascripts/effects.js
      &lt;span class="passed"&gt;remove&lt;/span&gt;  public/javascripts/prototype.js
      &lt;span class="passed"&gt;create&lt;/span&gt;  public/javascripts/jquery.min.js
      &lt;span class="passed"&gt;create&lt;/span&gt;  public/javascripts/jquery.js
    &lt;span class="failed"&gt;conflict&lt;/span&gt;  public/javascripts/rails.js
Overwrite /Users/asalicetti/rails/apps_for_asciicasts/ep229/blog/public/javascripts/rails.js? (enter &amp;quot;h&amp;quot; for help) [Ynaqdh] Y
       &lt;span class="forced"&gt;force&lt;/span&gt;  public/javascripts/rails.js
&lt;/pre&gt;       

&lt;p&gt;Una delle cose pi&amp;ugrave; utili del gem jquery-rails &amp;egrave; che ridefinisce in automatico i default che sono inclusi quando si usa la linea:&lt;/p&gt;

&lt;pre class="ruby"&gt;
&amp;lt;%= javascript_include_tag :defaults %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;nel nostro file di layout, per cui non c&amp;rsquo;&amp;egrave; bisogno di fare modifiche l&amp;agrave;.&lt;/p&gt;

&lt;h3&gt;Configurare Polling&lt;/h3&gt;

&lt;p&gt;Ora che abbiamo configurato jQuery nella nostra applicazione, possiamo cominciare a fare il lavoro necessario per l&amp;rsquo;auto-aggiornamento dei commenti. Ci sono due modi in cui possiamo affrontare il problema. Uno prevede l&amp;rsquo;utilizzo del polling. La nostra applicazione pu&amp;ograve; inviare delle richieste AJAX al server a periodi di tempo regolari per capire se il numero dei commenti &amp;egrave; cambiato. L&amp;rsquo;alternativa &amp;egrave; di usare &lt;a href="http://en.wikipedia.org/wiki/WebSockets"&gt;WebSockets&lt;/a&gt; per fornire una connessione permanente al server e ricevere in push le notifiche da esso non appena sono disponibili. Il polling &amp;egrave; la scelta pi&amp;ugrave; semplice fra le due, considerato anche che WebSockets non &amp;egrave; ancora supportato da tutti i browser e che necessiterebbe della stesura di una maggior quantit&amp;agrave; di codice e introdurrebbe anche una nuova dipendenza con una libreria di terzi, tipo &lt;a href="http://github.com/lifo/cramp"&gt;Cramp&lt;/a&gt; per funzionare. Non abbiamo bisogno di un sincronismo cos&amp;igrave; stretto per il nostro caso, per cui un ritardo di qualche secondo &amp;egrave; perfettamente accettabile e per questo seguiremo l&amp;rsquo;approccio a polling.&lt;/p&gt;

&lt;p&gt;Scriveremo il JavaScript che si occuper&amp;agrave; di fare le richieste in polling alla ricerca di cambiamenti nel file &lt;code&gt;application.js&lt;/code&gt;. Questo file &amp;egrave; presente in tutte le pagine dell&amp;rsquo;applicazione, per cui dovremo anche assicurarci che lo stesso esegua solamente nelle pagine che contengono commenti al loro interno. Il codice per il polling &amp;egrave; il seguente:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
$(function () {
  if ($(&amp;#x27;#comments&amp;#x27;).length &amp;gt; 0) {
    setTimeout(updateComments, 10000);
  }
});

function updateComments() {
  $.getScript(&amp;#x27;/comments.js&amp;#x27;);
  setTimeout(updateComments, 10000);
}
&lt;/pre&gt;

&lt;p&gt;Il codice riportato qui sopra comincia con una chiamata alla funzione jQuery &lt;code&gt;$&lt;/code&gt;. Quando questa funzione viene chiamata con un argomento di tipo funzione, come in questo caso, il codice all&amp;rsquo;interno della funzione esegue solo dopo che il DOM della pagina &amp;egrave; stato caricato completamente. In questo caso, quando il DOM si carica, controlliamo se la pagina corrente &amp;egrave; quella di un articolo, cercando la presenza di un elemento con &lt;code&gt;id&lt;/code&gt; uguale a &lt;code&gt;comments&lt;/code&gt;. Se lo si trova, allora usiamo la &lt;code&gt;setTimeout&lt;/code&gt; per chiamare la funzione &lt;code&gt;updateComments&lt;/code&gt; dopo un ritardo di dieci secondi.&lt;/p&gt;

&lt;p&gt;All&amp;rsquo;interno della funzione &lt;code&gt;updateComments&lt;/code&gt; vogliamo recuperare tutti i commenti aggiornati per l&amp;rsquo;articolo. Ci sono molti modi per farlo. Potremmo chiedere al server i nuovi commenti in formato JSON e usarli per creare l&amp;rsquo;HTML per i nuovi commenti, ma in questo caso il problema sarebbe che la &lt;code&gt;updateComments&lt;/code&gt; dovrebbe poi generare l&amp;rsquo;HTML corretto per questi nuovi commenti. Sarebbe pi&amp;ugrave; semplice generare l&amp;rsquo;HTML gi&amp;agrave; lato server e restituire il JavaScript che aggiorner&amp;agrave; la pagina per aggiungere tale HTML al posto giusto.&lt;/p&gt;

&lt;p&gt;Per fare tutto questo, usiamo la funzione jQuery &lt;code&gt;getScript&lt;/code&gt;. Se passiamo a questa funzione un URL, essa far&amp;agrave; una richiesta AJAX a tale URL ed eseguir&amp;agrave; qualsiasi script che le verr&amp;agrave; restituito in risposta. Useremo dunque la &lt;code&gt;getScript&lt;/code&gt; per chiamare la action &lt;code&gt;index&lt;/code&gt; del &lt;code&gt;CommentsController&lt;/code&gt; con un formato JavaScript. Dobbiamo aggiungere alcuni parametri di query all&amp;rsquo;URL affinch&amp;egrave; la action sappia quali commenti dovrebbero esserci restituiti, ma ritorneremo su questo punto in seguito.&lt;/p&gt;

&lt;p&gt;Dopo che la &lt;code&gt;getScript&lt;/code&gt; ha completato la sua esecuzione, invochiamo nuovamente la &lt;code&gt;setTimeout&lt;/code&gt;, affinch&amp;egrave; la &lt;code&gt;updateComments&lt;/code&gt; sia nuovamente chiamata dopo dieci secondi. Avremmo potuto usare la &lt;code&gt;setInterval&lt;/code&gt; al posto della &lt;code&gt;setTimeout&lt;/code&gt; per il controllo dell&amp;rsquo;esistenza dell&amp;rsquo;elemento dei commenti, in modo tale da non dover richiamare la funzione anche qui, ma in realt&amp;agrave; c&amp;rsquo;&amp;egrave; un vantaggio nel seguire il nostro approccio. Se avessimo utilizzato la &lt;code&gt;setInterval&lt;/code&gt;, di conseguenza la &lt;code&gt;updateComments&lt;/code&gt; sarebbe stata chiamata ogni dieci secondi a prescindere dal tempo necessario alla risposta AJAX. Invece, per come l&amp;rsquo;abbiamo implementata noi, tale richiesta di aggiornamento verr&amp;agrave; fatta sempre dieci secondi dopo che ci &amp;egrave; arrivata la risposta: in questo modo evitiamo di sovraccaricare ulteriormente il server quando &amp;egrave; gi&amp;agrave; molto carico di suo.&lt;/p&gt;

&lt;p&gt;Al momento, il &lt;code&gt;CommentsController&lt;/code&gt; non ha una action &lt;code&gt;index&lt;/code&gt;, per cui dovremo scriverla. Dovr&amp;agrave; recuperare gli opportuni commenti usando i parametri passati dal JavaScript di prima, ma per ora lasciamo vuoto il metodo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/comments_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def index

end
&lt;/pre&gt;

&lt;p&gt;Dovremo anche avere un template JavaScript da associare alla action. In esso, sempre momentaneamente, metteremo del codice di test per controllare che il polling stia funzionando a dovere:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/index.js.erb&lt;/p&gt;
&lt;pre class="javascript"&gt;
alert(&amp;#x27;Comments go here&amp;#x27;);
&lt;/pre&gt;

&lt;p&gt;Facendo ripartire il server e visitando la pagina dell&amp;rsquo;articolo, ora vedremo comparire un alert circa ogni dieci secondi dopo che la pagina si &amp;egrave; caricata, che significa che il JavaScript di sopra viene restituito dal server ed eseguito correttamente sul client:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/456/original/E229I01.png" width="824" height="504" alt="Viene mostrato un alert al momento del polling."/&gt;
&lt;/div&gt;

&lt;h3&gt;Recupero dei commenti corretti&lt;/h3&gt;

&lt;p&gt;Ora che il polling funziona, il prossimo passo &amp;egrave; quello di recuperare i commenti significativi. Dobbiamo aggiungere due parametri alla chiamata della action &lt;code&gt;index&lt;/code&gt; del &lt;code&gt;CommentController&lt;/code&gt;: l&amp;rsquo;&lt;code&gt;id&lt;/code&gt; dell&amp;rsquo;articolo corrente e un timestamp, in modo tale che sappiamo quali commenti recuperare:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
function updateComments() {
  $.getScript(&amp;#x27;/comments.js?article_id=&amp;#x27; + article_id + &amp;quot;&amp;amp;after=&amp;quot; + after);
  setTimeout(updateComments, 10000);
}
&lt;/pre&gt;

&lt;p&gt;Ci&amp;ograve; che dobbiamo ancora capire del codice sopra &amp;egrave; da dove prendere i valori per le variabili &lt;code&gt;article_id&lt;/code&gt; e &lt;code&gt;after&lt;/code&gt;, che non abbiamo ancora definito. In questo caso possiamo generare i valori in Rails e passarli al JavaScript dal documento HTML. Questa applicazione usa HTML 5, per cui possiamo utilizzare gli attributi data per aggiungere dati al documento.&lt;/p&gt;

&lt;p&gt;Aggiungeremo gli attributi al codice della vista relativa alla action &lt;code&gt;show&lt;/code&gt; del &lt;code&gt;ArticleController&lt;/code&gt;. Gli attributi data possono avere un qualsiasi nome, purch&amp;egrave; iniziante per &lt;code&gt;data-&lt;/code&gt;, per cui aggiungeremo un attributo &lt;code&gt;data-id&lt;/code&gt; al &lt;code&gt;div&lt;/code&gt; contenitore dell&amp;rsquo;articolo, con valore pari all&amp;rsquo;&lt;code&gt;id&lt;/code&gt; dell&amp;rsquo;articolo e in modo analogo, nel &lt;code&gt;div&lt;/code&gt; contenitore dei commenti, aggiungeremo un nuovo attributo &lt;code&gt;data-time&lt;/code&gt;, contenente il valore &lt;code&gt;created_at&lt;/code&gt; del commento, convertito a intero:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/articles/show.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;% title @article.name %&amp;gt;

&amp;lt;div id=&amp;quot;article&amp;quot; data-id=&amp;quot;&amp;lt;%= @article.id %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;%= simple_format @article.content %&amp;gt;
  
  &amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Back to Articles&amp;quot;, articles_path %&amp;gt;&amp;lt;/p&amp;gt;
  
  &amp;lt;% unless @article.comments.empty? %&amp;gt;
    &amp;lt;h2&amp;gt;&amp;lt;%= pluralize(@article.comments.size, &amp;#x27;commment&amp;#x27;) %&amp;gt;&amp;lt;/h2&amp;gt;
    
    &amp;lt;div id=&amp;quot;comments&amp;quot;&amp;gt;
    &amp;lt;% for comment in @article.comments %&amp;gt;
      &amp;lt;div class=&amp;quot;comment&amp;quot; data-time=&amp;quot;&amp;lt;%= comment.created_at.to_i %&amp;gt;&amp;quot;&amp;gt;
        &amp;lt;strong&amp;gt;&amp;lt;%= comment.name %&amp;gt;&amp;lt;/strong&amp;gt;
        &amp;lt;em&amp;gt;on &amp;lt;%= comment.created_at.strftime(&amp;#x27;%b %d, %Y at %I:%M %p&amp;#x27;) %&amp;gt;&amp;lt;/em&amp;gt;
        &amp;lt;%= simple_format comment.content %&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;% end %&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;% end %&amp;gt;
  
  &amp;lt;h3&amp;gt;Add your comment&amp;lt;/h3&amp;gt;
  &amp;lt;%= render :partial =&amp;gt; &amp;#x27;comments/form&amp;#x27; %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Possiamo ora ritornare alla funzione &lt;code&gt;updateComments&lt;/code&gt; e impostare i valori delle variabili &lt;code&gt;article_id&lt;/code&gt; e &lt;code&gt;after&lt;/code&gt; da quegli attributi data. Ottenere l&amp;rsquo;&lt;code&gt;id&lt;/code&gt; dell&amp;rsquo;articolo &amp;egrave; semplice: lo prendiamo banalmente dall&amp;rsquo;elemento che ha &lt;code&gt;id&lt;/code&gt; uguale a &lt;code&gt;article&lt;/code&gt;. Ci potrebbero invece essere molti commenti nella pagina e ci&amp;ograve; che ci occorre &amp;egrave; solo l&amp;rsquo;ultimo, per cui useremo il selettore &lt;code&gt;.comment:last&lt;/code&gt; per identificarlo, dopodich&amp;egrave; leggeremo il suo attributo &lt;code&gt;data-time&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
function updateComments() {
  var article_id = $(&amp;#x27;#article&amp;#x27;).attr(&amp;#x27;data-id&amp;#x27;);
  var after = $(&amp;#x27;.comment:last&amp;#x27;).attr(&amp;#x27;data-time&amp;#x27;);
  $.getScript(&amp;#x27;/comments.js?article_id=&amp;#x27; + article_id + &amp;quot;&amp;amp;after=&amp;quot; + after);
  setTimeout(updateComments, 10000);
}
&lt;/pre&gt;

&lt;p&gt;Ora che abbiamo a disposizione i valori per entrambe le variabili, possiamo usarli per recuparere i soli commenti che sono stati creati per quell&amp;rsquo;articolo dopo la data dell&amp;rsquo;ultimo presente in pagina.&lt;/p&gt;

&lt;p&gt;E&amp;rsquo; una buona idea quando si fa qualcosa di simile, controllare i log di sviluppo per accertarsi che tutto sembri funzionare come dovrebbe. Se visitiamo la pagina degli articoli e poi guardiamo i log, vedremo che la richiesta per i commenti in JavaScript viene fatta ogni dieci secondi pi&amp;ugrave; o meno, come ci aspettavamo a anche i parametri sembrano a posto:&lt;/p&gt;

&lt;pre class="terminal"&gt;
Started GET &amp;quot;/comments.js?article_id=1&amp;amp;after=1283173233&amp;quot; for 127.0.0.1 at 2010-09-02 19:58:53 +0100
  Processing by CommentsController#index as JS
  Parameters: {&amp;quot;article_id&amp;quot;=&amp;gt;&amp;quot;1&amp;quot;, &amp;quot;after&amp;quot;=&amp;gt;&amp;quot;1283173233&amp;quot;}
Rendered comments/index.js.erb (0.4ms)
Completed 200 OK in 41ms (Views: 41.1ms | ActiveRecord: 0.0ms)


Started GET &amp;quot;/comments.js?article_id=1&amp;amp;after=1283173233&amp;quot; for 127.0.0.1 at 2010-09-02 19:59:07 +0100
  Processing by CommentsController#index as JS
  Parameters: {&amp;quot;article_id&amp;quot;=&amp;gt;&amp;quot;1&amp;quot;, &amp;quot;after&amp;quot;=&amp;gt;&amp;quot;1283173233&amp;quot;}
Rendered comments/index.js.erb (0.4ms)
Completed 200 OK in 34ms (Views: 33.6ms | ActiveRecord: 0.0ms)
&lt;/pre&gt;

&lt;p&gt;ora che sappiamo che i parametri sono passati correttamente, possiamo usarli nella action &lt;code&gt;index&lt;/code&gt; del &lt;code&gt;CommentsController&lt;/code&gt; per avere i nuovi commenti:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/comments_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def index
  @comments = Comment.where(&amp;quot;article_id = ? and created_at &amp;gt; ?&amp;quot;, params[:article_id], Time.at(params[:after].to_i))
end
&lt;/pre&gt;  

&lt;p&gt;Possiamo ora aggiornare il template associato al JavaScript affinch&amp;egrave; mostri i commenti anzich&amp;egrave; mostrare solo un alert. Prima di farlo, comunque, dobbiamo spostare il codice che mostra un commento fuori dalla vista &lt;code&gt;show&lt;/code&gt; dell&amp;rsquo;articolo, in un partial separato, in modo tale che lo si possa usare nel template del Javascript. Muoveremo dunque tale codice in un nuovo file partial chiamato &lt;code&gt;_comment.html.erb&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/_comment.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;div class=&amp;quot;comment&amp;quot; data-time=&amp;quot;&amp;lt;%= comment.created_at.to_i %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;strong&amp;gt;&amp;lt;%= comment.name %&amp;gt;&amp;lt;/strong&amp;gt;
  &amp;lt;em&amp;gt;on &amp;lt;%= comment.created_at.strftime(&amp;#x27;%b %d, %Y at %I:%M %p&amp;#x27;) %&amp;gt;&amp;lt;/em&amp;gt;
  &amp;lt;%= simple_format comment.content %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Dopodich&amp;egrave;, nella vista relativa alla action &lt;code&gt;show&lt;/code&gt;, possiamo semplicemente renderizzare il partial per la collezione di commenti:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/show.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;% title @article.name %&amp;gt;

&amp;lt;div id=&amp;quot;article&amp;quot; data-id=&amp;quot;&amp;lt;%= @article.id %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;%= simple_format @article.content %&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Back to Articles&amp;quot;, articles_path %&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;% unless @article.comments.empty? %&amp;gt;
    &amp;lt;h2&amp;gt;&amp;lt;%= pluralize(@article.comments.size, &amp;#x27;commment&amp;#x27;) %&amp;gt;&amp;lt;/h2&amp;gt;
    &amp;lt;div id=&amp;quot;comments&amp;quot;&amp;gt;
    &amp;lt;%= render @article.comments %&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;lt;h3&amp;gt;Add your comment&amp;lt;/h3&amp;gt;
  &amp;lt;%= render :partial =&amp;gt; &amp;#x27;comments/form&amp;#x27; %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Possiamo aggiornare il template JavaScript della pagina &lt;code&gt;index&lt;/code&gt; dei commenti affinch&amp;egrave; generi il JavaScript per aggiornare i commenti:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/index.js.erb&lt;/p&gt;
&lt;pre class="javascript"&gt;
$(&amp;#x27;#comments&amp;#x27;).append(&amp;quot;&amp;lt;%= escape_javascript(raw render(@comments))%&amp;gt;&amp;quot;);
&lt;/pre&gt;

&lt;p&gt;Questo codice renderizza la collezione di commenti usando il partial che abbiamo appena scritto. Dobbiamo racchiudere l&amp;rsquo;output del partial in un metodo &lt;code&gt;raw&lt;/code&gt;, poich&amp;egrave; per default Rails 3 farebbe l&amp;rsquo;escape dell&amp;rsquo;HTML e noi non lo vogliamo. Poi dobbiamo chiamare l&amp;rsquo;&lt;code&gt;escape_javascript&lt;/code&gt; sull&amp;rsquo;output di quel comando, affinch&amp;egrave; l&amp;rsquo;HTML sia sicuro per essere racchiuso in una stringa JavaScript. Il JavaScript che viene rimandato indietro al browser aggiunge questa stringa in fondo al &lt;code&gt;div&lt;/code&gt; dei commenti.&lt;/p&gt;

&lt;p&gt;Possiamo dare un&amp;rsquo;occhiata alla pagina nel browser, ora, per vedere se i commenti si aggiornano automaticamente ed otteniamo dei risultati solo parziali. Sebbene i commenti siano aggiornati, continuiamo a vedere che l&amp;rsquo;ultimo commento continua ad essere aggiunto:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/457/original/E229I02.png" width="816" height="570" alt="L&amp;rsquo;ultimo commento viene aggiunto di continuo."/&gt;
&lt;/div&gt;

&lt;p&gt;Ci&amp;ograve; avviene perch&amp;egrave; quando otteniamo i nuovi commenti, il timestamp che passiamo ha una precisione al secondo. In questo caso stiamo chiedendo i commenti posteriori alle 13:00:33 del 30 agosto 2010, ma se guardiamo sul database, il commento &amp;egrave; stato inserito alle 13:00:33.892041 e, anche se apparentemente dei millisecondi non ce ne potrebbe fregare di meno, per il controllo che facciamo, questa minima differenza &amp;egrave; sufficiente a far considerare il commento sul database posteriore come timestamp a quello passato come parametro in query. Per sistemare questa cosa, dobbiamo arrotondare e chiedere i commenti lasciati almeno un secondo dopo l&amp;rsquo;ultimo commento attuale, per cui aggiungiamo &lt;code&gt;1&lt;/code&gt; al valore intero ricevuto dal parametro nella query:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/comments_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def index
  @comments = Comment.where(&amp;quot;article_id = ? and created_at &amp;gt; ?&amp;quot;, params[:article_id], Time.at(params[:after].to_i + 1))
end
&lt;/pre&gt;

&lt;p&gt;Ora non vedremo pi&amp;ugrave; l&amp;rsquo;ultimo commento comparire di continuo. Possiamo testare che l&amp;rsquo;aggiornamento funziona, aprendo la pagina degli articoli su due finestre del browser differenti, inserendo un commento in una e controllando che appaia anche nell&amp;rsquo;altra:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/458/original/E229I03.png" width="818" height="345" alt="Aggiunta di un commento nella prima finestra del browser."/&gt;
&lt;/div&gt;

&lt;p&gt;Dopo pochi secondi il polling interviene e il commento compare sull&amp;rsquo;altra finestra del browser.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/459/original/E229I04.png" width="816" height="448" alt="Il nuovo commento viene mostrato automaticamente nell&amp;rsquo;altra finestra del browser."/&gt;
&lt;/div&gt;

&lt;h3&gt;Aggiornamento del contatore dei commenti&lt;/h3&gt;

&lt;p&gt;Anche se il nuovo commento &amp;egrave; stato correttamente aggiunto per polling, la testata che mostra il numero totale dei commenti non &amp;egrave; stata aggiornata di conseguenza. Sistemiamo la cosa:&lt;/p&gt;

&lt;p&gt;Possiamo aggiornare il contatore dei commenti nello stesso file utilizzato anche per l&amp;rsquo;aggiornamento dei commenti stessi. Di primo impatto, la cosa ovvia da fare potrebbe essere qualcosa del genere:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/index.js.erb&lt;/p&gt;
&lt;pre class="javascript"&gt;
$(&amp;#x27;#comments&amp;#x27;).append(&amp;quot;&amp;lt;%= escape_javascript(raw render(@comments))%&amp;gt;&amp;quot;);
$(&amp;#x27;#article h2&amp;#x27;).text(&amp;#x27;&amp;lt;%= @comments.first.article.comments.size %&amp;gt; comments&amp;#x27;);
&lt;/pre&gt;

&lt;p&gt;Questo approccio implica tuttavia una chiamata al database per ottenere il totale dei commenti e dal momento che questo codice sar&amp;agrave; chiamato piuttosto frequentemente, ha senso cercare di evitarlo, se possiamo. Possiamo ottenere il totale dei commenti direttamente dalla pagina, banalmente contanto il numero di elementi di classe &lt;code&gt;comment&lt;/code&gt; presenti sulla pagina stessa:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/index.js.erb&lt;/p&gt;
&lt;pre class="javascript"&gt;
$(&amp;#x27;#comments&amp;#x27;).append(&amp;quot;&amp;lt;%= escape_javascript(raw render(@comments))%&amp;gt;&amp;quot;);
$(&amp;#x27;#article h2&amp;#x27;).text($(&amp;#x27;.comment&amp;#x27;).length + &amp;#x27; comments&amp;#x27;);
&lt;/pre&gt;

&lt;p&gt;Questo codice non gestir&amp;agrave; la pluralizzazione, per cui mostrer&amp;agrave; sempre la dicitura &amp;ldquo;commenti&amp;rdquo;, anche se c&amp;rsquo;&amp;egrave; solo un commento, ma tralasciamo questo particolare. Come tocco finale, aggiungeremo una clausola affinch&amp;egrave; il JavaScript sia impostato solo se ci sono dei nuovi commenti:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/comments/index.js.erb&lt;/p&gt;
&lt;pre class="javascript"&gt;
&amp;lt;% unless @comments.empty? %&amp;gt;
$(&amp;#x27;#comments&amp;#x27;).append(&amp;quot;&amp;lt;%= escape_javascript(raw render(@comments))%&amp;gt;&amp;quot;);
$(&amp;#x27;#article h2&amp;#x27;).text($(&amp;#x27;.comment&amp;#x27;).length + &amp;#x27; comments&amp;#x27;);
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Quando aggiungiamo un altro commento in un browser, ora, i commenti vengono aggiornati anche nell&amp;rsquo;altra finestra del browser, aperta sulla stessa pagina, insieme al contatore:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/460/original/E229I05.png" width="816" height="448" alt="il contatore dei commenti ora viene aggiornato correttamente."/&gt;
&lt;/div&gt;

&lt;h3&gt;Un&amp;rsquo;ultima correzione&lt;/h3&gt;

&lt;p&gt;C&amp;rsquo;&amp;egrave; solo ancora un piccolo problema con questo codice che deve essere sistemato. Nella funzione &lt;code&gt;updateComments&lt;/code&gt;, il valore della variabile &lt;code&gt;after&lt;/code&gt; &amp;egrave; impostata da un attributo preso dall&amp;rsquo;ultimo commento presente sulla pagina. Se non ci sono commenti per un certo articolo, allora questo valore sar&amp;agrave; vuoto, per cui dovremo fare in modo che la variabile sia associata, in questi casi, al valore di default di 0, affinch&amp;egrave; siano restituiti tutti i commenti:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
$(function () {
  if ($(&amp;#x27;#comments&amp;#x27;).length &amp;gt; 0) {
    setTimeout(updateComments, 10000);
  }
});

function updateComments() {
  var article_id = $(&amp;#x27;#article&amp;#x27;).attr(&amp;#x27;data-id&amp;#x27;);
  if ($(&amp;#x27;.comment&amp;#x27;).length &amp;gt; 0) {
    var after = $(&amp;#x27;.comment:last&amp;#x27;).attr(&amp;#x27;data-time&amp;#x27;);
  }
  else {
    var after = 0;
  }
  
  $.getScript(&amp;#x27;/comments.js?article_id=&amp;#x27; + article_id + &amp;quot;&amp;amp;after=&amp;quot; + after);
  setTimeout(updateComments, 10000);
}
&lt;/pre&gt;

&lt;p&gt;Ci sono altre cose che potrebbero essere migliorate. Per esempio, potremmo rendere l&amp;rsquo;intervallo di aggiornameno dinamico, affinch&amp;egrave;, se l&amp;rsquo;ultimo commento &amp;egrave; stato aggiunto molto tempo fa, diciamo per esempio pi&amp;ugrave; di un&amp;rsquo;ora fa, la frequenza del polling sia ridotta. In questo modo si riduce il carico sul server quando si osservano articoli che non hanno avuto commenti di recente.&lt;/p&gt;

&lt;p&gt;Potremmo anche migliorare un po&amp;rsquo; l&amp;rsquo;interfaccia utente, aggiungendo un evidenziazione, per indicare quando viene aggiunto un nuovo commento alla pagina. In altrenativa, potremmo aggiungere un link che indica che ci sono nuovi commenti disponibili e che li mostra solamente al click dell&amp;rsquo;utente sullo stesso.&lt;/p&gt;</description>
      <pubDate>Mon, 20 Sep 2010 09:00:01 +0000</pubDate>
      <guid>http://it.asciicasts.com/episodes/229-fare-polling-per-verificare-modifiche</guid>
      <link>http://it.asciicasts.com/episodes/229-fare-polling-per-verificare-modifiche</link>
    </item>
  </channel>
</rss>

