#227 Upgrading to Rails 3 Part 3
In questo episodio chiudiamo la serie sull’aggiornamento di un’applicazione Rails 2 a Rails 3. Abbiamo fatto buoni progressi fino ad ora; abbiamo fatto passare tutti i test dell’applicazione e abbiamo usato il plugin Rails upgrade per trovare una soluzione alla maggior parte delle aree in cui c’era bisogno di un intervento di aggiornamento a Rails 3. Ci sono ancora alcune cose che hanno bisogno di essere sistemate sul piano delle viste, tuttavia, ed è ciò che affronteremo in questo episodio.
Rimozione dei warning di deprecazione
Prima di iniziare a sistemare le viste, daremo ancora uno sguardo ai test. Al termine dello scorso episodio tutti i test applicativi erano passati, ma c’erano un gran numero di warning relativi a deprecazioni. Rilanciamo ora questi testi per vedere se riusciamo a ridurre il numero di questi warning:
$ rake spec # large amount of output snipped. .DEPRECATION WARNING: error_messages_for was removed from Rails and is now available as a plugin. Please install it with `rails plugin install git://github.com/rails/dynamic_form.git`. (called from _app_views_sponsors__form_html_erb___2363957037552137609_2171491000_4161310651677273387 at /Users/eifion/rails/apps_for_asciicasts/ep227/railscasts/app/views/sponsors/_form.html.erb:2) <span class="passed">...................................................</span> <span class="passed">Finished in 3.24 seconds</span> <span class="passed">152 examples, 0 failures</span>
Questo test passa ancora, ma ci sono molti warning. Per fortuna si tratta per la maggior parte di warning duplicati, per cui non ci vorrà molto a rimuoverli.
Abbiamo rimosso la maggior parte dell’output del comando rake spec qui sopra, ma abbiamo lasciato l’ultimo warning. I metodi error_messages_for
e error_messages_on
sono stati deprecati in Rails 3 e li possiamo sostituire con del codice specifico che iteri sugli errors.full_messages
del modello per mostrare gli errori. I vecchi metodi sono ancora disponibili come plugin, comunque, per cui optiamo per la soluzione più semplice e ci appoggiamo a quello. Le istruzioni per installarlo sono riportate nel messaggio di deprecazione stesso:
$ rails plugin install git://github.com/rails/dynamic_form.git Initialized empty Git repository in /Users/asalicetti/rails/apps_for_asciicasts/ep227/railscasts/vendor/plugins/dynamic_form/.git/ remote: Counting objects: 22, done. remote: Compressing objects: 100% (17/17), done. remote: Total 22 (delta 2), reused 0 (delta 0) Unpacking objects: 100% (22/22), done. From git://github.com/rails/dynamic_form * branch HEAD -> FETCH_HEAD
Installato il plugin, rilanciando rake spec
di nuovo, il warning sarà scomparso. Ci sono altri errori, tuttavia, il più frequente dei quali sembra essere questo:
DEPRECATION WARNING: subclasses is deprecated and will be removed from Rails 3.0 (use descendants instead). (called from block (2 levels) in load_models at /Users/asalicetti/.rvm/gems/ruby-1.9.2-rc2/gems/thinking-sphinx-2.0.0.rc1/lib/thinking_sphinx/context.rb:58)
Questo errore è lanciato dalla libreria Thinking Sphinx. Ogni volta che si hanno degli errori provenienti da dei plugin, vale la pena contollare l’issue tracker per tali plugin per capire se esistono già delle segnalazioni relative allo stesso problema riscontrato. Se così non fosse, ne possiamo aggiungere una nuova noi nella speranza che venga risolta nella successiva release. (In alternativa vi potreste sempre creare un fork del codice del plugin e sistemarlo voi stessi...)
Nel caso del plugin Thinking Sphinx, questo problema è già stato segnalato e sistemato, ma non è stato ancora incluso nell’ultima release del gem nel momento in cui stiamo scrivendo. Per rimuovere questo warning, possiamo dire a bundler di prendere il codice di Thinking Sphinx da un repository git, anzichè da un gem.
Per cui nel nostro Gemfile
, anzichè includere Thinking Sphinx in questo modo:
gem 'thinking-sphinx', '>=2.0.0.rc1', :require => 'thinking_sphinx'
lo includiamo in quest’altro:
gem 'thinking-sphinx', :require => 'thinking_sphinx', :git => "git://github.com/freelancing-god/thinking-sphinx.git", :branch => "rails3"
Dobbiamo rilanciare bundle install
in modo che bundler scarichi Thinking Sphinx dal suo repository git. La nostra applicazione ora utilizzerà questa versione anzichè quella presente nell’ultimo gem. Quando ora lanciamo le nostre specs, passeranno tutte senza messaggi di warning:
$ rake spec <span class="passed">........................................................................................................................................................</span> <span class="passed">Finished in 3.3 seconds</span> <span class="passed">152 examples, 0 failures</span>
Sistemazione le viste
Tolti di mezzo i warning sulle deprecazioni, ci possiamo concentrare sulle viste. Quando lanciamo l’applicazione, il primo errore che salta fuori è che la barra laterale non compare più nella pagina degli episodi:
Una porzione di pagina grande come questa dovrebbe essere coperta da un test, quantomeno per verificarne la sua presenza. Se stessimo aggiornando l’applicazione per un ambiente di produzione, allora scriveremmo un test per coprire questa cosa, ma siccome non è questo il caso, in questa sede non lo faremo.
Guardando dentro al file di layout, vediamo che il codice che genera la barra laterale è questo:
<%= yield(:side) || render(:partial => 'shared/side') %>
Questo codice fa lo yield
dei contenuti laterali e, nel caso in cui questi restituiscano nil
, renderizza il partial side al loro posto. Il problema in questo caso è che nelle prime versioni di Rails yield
restituiva nil
se mancava la chiamata opportuna a content_for
, mentre invece in Rails 3 restituisce una stringa vuota, per cui la seconda parte del codice non verrà mai invocata in Rails 3.
Per sistemare la cosa, possiamo usare il metodo content_for?
, che restituisce true
se tale area contenitore è stata definita sulla pagina. Se lo è stata, ne mostra il contenuto, altrimenti faremo il rendering della barra laterale:
<%= content_for?(:side) ? yield(:side) : render(:partial=> 'shared/side') %>
Al ricaricamento della pagina, ora la barra laterale verrà mostrata correttamente:
Ci sono ancora altri problemi da risolvere nella vista. Se guardiamo la pagina del singolo episodio, vediamo che viene fatto l’escape della parte "mostra note":
Il contenuto di quella pagina passa attraverso il metodo textilize
che è definito nel module ApplicationHelper
:
module ApplicationHelper def textilize(text) Textilizer.new(text).to_html unless text.blank? end end
Questo metodo restituisce dell’HTML sottoforma di stringa. In Rails 3 se si vuole passare dell’HTML a una vista al fine di mostrarla renderizzata all’utente, quest’ultima deve essere segnata come HTML-safe, altrimenti ne viene fatto l’escape in automatico. Per marcare la stringa come "safe", dobbiamo semplicemente invocare su di essa il metodo html_safe
:
module ApplicationHelper def textilize(text) Textilizer.new(text).to_html.html_safe unless text.blank? end end
Ora la stringa è stata marcata come sicura dal punto di vista dell’HTML, per cui non ne verrà più fatto l’escape. Tutto ciò è stato trattato più in dettaglio nell’episodio 204 [guardalo, leggilo]. Al nuovo ricaricamento della pagina le note sono mostrate correttamente:
C’è rimasto un unico piccolo problema in questa pagina: la barra del titolo dovrebbe includere il nome dell’episodio. Questo problema è specifico del modo in cui sono gestiti i titoli in questa applicazione; per impostare il titolo si usa un metodo helper title
che imposta una variabile di istanza, anzichè usare un content_for
:
module LayoutHelper def title(page_title, show_title = true) @content_for_title = page_title.to_s @show_title = show_title end end
Per sistemare anche questa cosa, dovremmo impostare il contenuto del titolo usando il content_for
, in questo modo:
module LayoutHelper def title(page_title, show_title = true) content_for(:title, page_title.to_s) @show_title = show_title end end
Ora possiamo chiamare uno yield(:title)
nel layout per far sì che il titolo venga impostato correttamente. Potremmo passare il contenuto stesso in un blocco o, come in questo caso, come secondo argomento.
Sistemazione dei link di cancellazione
Il prossimo errore si trova nella sezione amministrativa del sito. Nella pagina riportata di sotto c’è una lista di oggetti di modello, ciascuno con un collegamento a “edit” e a “destroy”:
In questo caso il problema risiede nel link di “destroy”. Quando vi si clicca sopra, si viene ridiretti alla pagina della action show
della domanda anzichè alla destroy
. La ragione del fatto che la action delete
non viene chiamata è che il JavaScript usato per il collegamento di cancellazione è stato reso unobtrusive in Rails 3. Se diamo un’occhiata all’HTML di una delle domande, vedremo che il JavaScript non è più incluso nel tag del link di cancellazione. Di contro, ci sono due attributi custom HTML 5 che iniziano per data-
e ci dovrebbe anche essere del JavaScript in grado di leggere questi attributi e trasformare la richiesta (di default di tipo GET) in una richiesta di DELETE:
<tr> <td>What does the M stand for in MVC?</td> <td>model</td> <td><a href="/spam_questions/1/edit">Edit</a></td> <td><a href="/spam_questions/1" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Destroy</a></td> </tr>
Dal momento che questa applicazione utilizza jQuery, dobbiamo scaricare un file rails.js ad hoc dal progetto jquery-ujs. Se stessimo usando Prototype, non avremmo avuto bisogno di farlo, dal momento che il file corretto si sarebbe già trovato incluso nella cartella /public/javascripts
. Una volta scaricato il file e copiatolo nella cartella javascripts
, dobbiamo aggiungere un riferimento ad esso nella sezione HEAD del file di layout della nostra applicazione. Dobbiamo anche aggiungere il meta tag csrf per scongiurare le cross-site request forgeries:
<%= javascript_include_tag 'jquery', 'rails', 'application' %> <%= csrf_meta_tag %>
L’uso dell’unobtrusive JavaScript in Rails 3 è stato trattato nell’episodio 205 [guardalo, leggilo].
Visto che ci troviamo sul file di layout, approfittiamone per aggiornare l’applicazione all’uso di HTML 5, cambiando il DOCTYPE e il tag html
di apertura:
<!DOCTYPE html> <html>
Ci saranno altre cose che dovremo fare per rendere l’applicazione completamente valida per HTML 5 e potremo anche lanciare un validatore sul codice per scoprire quello che va modificato a tale scopo.
Col nuovo file rails.js
al suo posto, quando ricarichiamo la pagina delle spam question e proviamo a cancellarne una, ci verrà mostrata una popup di conferma JavaScript e la domanda sarà effettivamente cancellata se si clicca su OK per confermare:
L’ultima modifica che possiamo fare al codice della vista è quella di rimuovere qualsiasi chiamata al metodo h
. Nelle viste Rails 2, tutto l’output di cui volevamo fosse fatto l’escape doveva essere racchiuso nel metodo h
. In Rails 3 viene fatto automaticamente l’escape di tutto l’output, per cui quel codice non serve più. L’argomento è stato approfondito nell’episodio 204 [guardalo, leggilo]. Lasciare il metodo non genererà dei problemi, ma renderà il codice della vista inutilmente più complicato.
Rimozione di file obsoleti
Stiamo volgendo al termine dell’aggiornamento; funziona tutto, ma vogliamo ancora ripulire il progetto da alcuni file di cui non avremo più bisogno in futuro. Quando abbiamo rigenerato l’applicazione con Rails 3, è stato creata una nuova pagina di benvenuto che possiamo rimuovere:
$ rm public/index.html
La stessa cosa dicasi per il file di immagine di Rails che doveva essere mostrato nella pagina di benvenuto:
$ rm public/images/rails.png
Ci sono anche dei file sotto nella cartella /script
che non servono più in Rails 3 e che si possono togliere:
$ ls script about destroy process setup autospec generate rails setup_test console performance runner spec dbconsole plugin server spec_server
L’unico script necessario a Rails 3 fra questi è rails
; rimuoviamo gli altri.
Questo conclude la serie sull’aggiornamento di un’applicazione da Rails 2 a Rails 3. Ricordatevi che molte delle cose che abbiamo fatto erano specifiche dell’applicazione usata come esempio, Railscasts, e che non c’è modo di poter coprire tutte le casistiche di aggiornamento in un tutorial come questo. In generale, se incappate in warning di deprecazione o in messaggi di errore, ci sono sempre buone possibilità che qualcun’altro prima di voi si sia già trovato di fronte allo stesso problema e l’abbia risolto. Una ricerca su Google in genere porta anche alla soluzione in questi casi. Vale anche la pena consultare, se non lo avete già fatto, gli altri episodi che trattano di Rails 3.
La maggior parte dei problemi che potrete incontrare in fase di aggiornamento di una applicazione da Rails 2 a Rails 3, saranno comunque dovuti ai plugin installati per quella specifica applicazione. Il sito Rails Plugins contiene un elenco esaustivo di plugin ed indica anche per tutti se siano compatibili o meno con Rails 3. Se doveste avere dei problemi con un particolare plugin, controllare nel suo repository Git se per caso esiste una versione (o un branch) compatibile con Rails 3.