#227 Upgrading to Rails 3 Part 3
Neste episódio, vamos terminar nossa série sobre a atualização de uma aplicação Rails 2 para o Rails 3. Fizemos um bom progresso até agora, temos todos os testes da aplicação passando e usamos o plugin de atualização do Rails para encontrar e corrigir a maioria das áreas que necessitam de atualização para o Rails 3. Ainda existem coisas que precisam ser corrigidas nas views e vamos nos concentrar nisso neste episódio.
Removendo Avisos de Código Obsoleto
Antes de começarmos consertando as views, vamos dar outra olhada nos testes. Até o final do último episódio, todos os testes da aplicação estavam passando, mas havia um grande número de avisos de código obsoleto (deprecated) mostrado enquanto executavam. Vamos executar os testes novamente, agora para ver se podemos reduzir o número de avisos.
$ 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>
Os testes continuam passando, mas ainda há um grande número de advertências. Felizmente, a maioria delas são duplicadas então não deve dar muito trabalho retirá-las.
Cortamos a maior parte da saída do rake spec
executado acima, mas deixamos o aviso final. Os métodos error_messages_for
e error_messages_on
estão obsoletos no Rails 3 e podemos substituí-los por um código personalizado que percorre o errors.full_messages
para exibir os erros. Os métodos antigos ainda estão disponíveis como um plugin, assim nós vamos tomar o caminho mais fácil e usar esse plugin. As instruções para instalá-lo foram mostradas no aviso acima.
$ rails plugin install git://github.com/rails/dynamic_form.git Initialized empty Git repository in /Users/eifion/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
Com o plugin instalado, quando executamos rake spec
novamente, o aviso desapareceu. Há outros erros, porém, e um dos que aparecem com frequência é o seguinte:
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/eifion/.rvm/gems/ruby-1.9.2-rc2/gems/thinking-sphinx-2.0.0.rc1/lib/thinking_sphinx/context.rb:58)
Esse erro é da biblioteca Thinking Sphinx. Se você estiver recebendo erros de um plugin, vale a pena verificar o issue tracker desse plugin para ver se existem problemas constantes relacionados com o erro que você está vendo. Senão podemos adicionar um e talvez isso seja corrigido para a próxima versão. (Alternativamente, você pode sempre dar fork no código e corrigir o erro você mesmo.)
No caso do Thinking Sphinx, esse problema já foi detectado e corrigido, mas não foi incluído na versão mais recente da gem no momento da escrita desse episódio. Para remover esse aviso de nossa aplicação, podemos dizer ao bundler para obter o código do Thinking Sphinx de um repositório git em vez de uma gem.
Assim, em nossa Gemfile, em vez de incluir Thinking Sphinx da seguinte forma:
gem 'thinking-sphinx', '>=2.0.0.rc1', :require => 'thinking_sphinx'
vamos incluí-lo assim:
gem 'thinking-sphinx', :require => 'thinking_sphinx', :git => "git://github.com/freelancing-god/thinking-sphinx.git", :branch => "rails3"
Temos que executar bundle install
novamente para que ele baixe o Thinking Sphinx do seu repositório git. Nossa aplicação agora usará essa versão em vez da última gem. Quando rodamos nossos specs novamente, todas passam sem avisos.
$ rake spec <span class="passed">........................................................................................................................................................</span> <span class="passed">Finished in 3.3 seconds</span> <span class="passed">152 examples, 0 failures</span>
Consertando as Views
Com os avisos de código obsoleto resolvidos, podemos nos concentrar nas views. Ao executarmos a aplicação, o primeiro erro que se destaca é a ausência da barra lateral na página de episódios.
Uma parte da página tão grande como essa deve ser coberta por um teste, mesmo que apenas para testar a sua existência. Se fôssemos atualizar essa aplicação para produção, então iríamos escrever um teste para cobrir essa funcionalidade, mas não vamos fazer isso aqui.
Se dermos uma olhada no arquivo de layout, o código que gera a barra lateral é o seguinte:
<%= yield(:side) || render(:partial => 'shared/side') %>
Esse código irá produzir o conteúdo da barra lateral e se ele retornar nil
será renderizado o partial da lateral em seu lugar. O problema aqui é que em versões anteriores do Rails, yield
retornava nil
se a chamada apropriada ao content_for
estivesse faltando na página, enquanto no Rails 3 retorna uma string vazia, então a segunda parte do código nunca será chamada.
Para corrigir isso, podemos usar o content_for?
que retorna true
se a área de conteúdo foi definida para uma página. Se tiver sido definida, vamos mostrar seu conteúdo, caso contrário vamos usar a barra lateral.
<%= content_for?(:side) ? yield(:side) : render(:partial=> 'shared/side') %>
Ao recarregar a página agora, a barra lateral é exibida.
Há ainda outros problemas nas views para serem corrigidos. Se formos ver a página de um único episódio, veremos que a exibição das notas está sendo escapada.
O conteúdo para aquela parte da página passa pelo método textilize
que é definido no módulo ApplicationHelper
.
module ApplicationHelper def textilize(text) Textilizer.new(text).to_html unless text.blank? end end
Esse método retorna um HTML como uma string. No Rails 3, se você vai passar uma string de HTML para ser exibida em uma view, a string deverá ser marcada como HTML-safe, caso contrário será automaticamente escapada. Para marcar a string como segura, só precisamos chamar o método html_safe
para ela.
module ApplicationHelper def textilize(text) Textilizer.new(text).to_html.html_safe unless text.blank? end end
Agora, a string foi marcada como segura e não será mais escapada. Isso é abordado com mais detalhes no episódio 204 [assistir, ler]. Ao recarregarmos a página novamente a exibição das notas é renderizada corretamente.
Há ainda um pequeno problema nessa página: a barra de título deve incluir o nome do episódio. Esse problema é específico para a forma como os títulos são tratados nessa aplicação. Um método helper title
é usado, o qual define uma variável de instância ao invés de usar content_for
para definir o título.
module LayoutHelper def title(page_title, show_title = true) @content_for_title = page_title.to_s @show_title = show_title end end
Para corrigir isso, devemos definir o conteúdo para o título usando content_for
, assim:
module LayoutHelper def title(page_title, show_title = true) content_for(:title, page_title.to_s) @show_title = show_title end end
Agora, quando chamamos yield(:title)
no layout, o título será definido corretamente. Podemos passar o conteúdo em si como um bloco ou, como temos aqui, como um segundo argumento.
Corrigindo Links de Destroy
O erro seguinte é na seção de administração da aplicação. Na página a seguir está uma lista de objetos do modelo, cada um com um link edit
e destroy
.
O problema aqui está com os links destroy
. Quando clicamos em um deles, seremos levados para a action show, em vez da action destroy
. A razão pela qual a ação de exclusão não é chamada, é que o JavaScript usado para os links destroy
foi feito não obstrutivo no Rails 3. Se olharmos no HTML para um dos links, nós vamos ver que o JavaScript não é mais embutido no link destroy
. Em vez disso, há dois atributos HTML 5 personalizados que começam com data-
e deve haver algum JavaScript que irá detectar esses atributos e alterar a requisição para uma requisição 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>
Como essa aplicação usa jQuery, é preciso baixar o arquivo rails.js personalizado do projeto jquery-UJS. Se estivéssemos usando Prototype, então não teríamos necessidade de fazer isso, pois o arquivo correto já está incluído no diretório /public/javascripts
. Fizemos o download do arquivo e copiamos para o diretório javascripts
, então vamos precisar adicionar uma referência a ele na tag head
do layout. Nós também precisamos adicionar uma meta tag csrf para prevenir ataques cross-site request forgery.
<%= javascript_include_tag 'jquery', 'rails', 'application' %> <%= csrf_meta_tag %>
O uso de JavaScript não obstrutivo no Rails 3 é abordado no episódio 205 [assistir, ler].
Como estamos no arquivo de layout, vamos atualizar a aplicação para usar HTML 5, alterando o DOCTYPE e a tag html
.
<!DOCTYPE html> <html>
Existem outras coisas que precisamos fazer para tornar a aplicação totalmente HTML 5. Podemos verificar o código através de um validador para descobrir o que tem que ser mudado.
Com o novo arquivo rails.js
no lugar, quando recarregarmos a página Spam Questions, e tentarmos deletar uma das perguntas, a confirmação JavaScript será mostrada e a pergunta será apagada, se clicarmos em OK.
A última alteração que podemos fazer com o código da view é remover todas as chamadas ao método h
. Nas views do Rails 2, qualquer saída que precisávamos escapar código HTML tinha que ser tratada com o método h
. Todas as saídas no Rails 3 são escapadas por padrão. Então podemos arrumar as views, passando por elas e eliminando esses métodos h
. Esse assunto foi coberto no episódio 204 [assistir, ler]. Deixar o método não irá causar quaisquer problemas, mas o código ficará mais limpo sem ele.
Removendo Arquivos Obsoletos
Estamos chegando ao final da atualização agora. Tudo está funcionando, mas precisamos eliminar alguns dos arquivos que não precisamos mais. Quando geramos a nova aplicação Rails 3, foi criada uma nova página de boas-vindas e esta terá que ser removida.
$ rm public/index.html
O mesmo se aplica a imagem do Rails que é mostrada na página de boas-vindas.
$ rm public/images/rails.png
Existem também os arquivos na pasta /script
que não são mais usados pelo Rails 3 e podem ser removidos.
$ ls script about destroy process setup autospec generate rails setup_test console performance runner spec dbconsole plugin server spec_server
Apenas o script rails
é usado pelo Rails 3 e assim podemos remover os outros, como console
, server
e assim por diante.
Isso é tudo para essa série sobre a atualização de uma aplicação Rails 2 para Rails 3. Tenha em mente que muitas coisas que nós cobrimos são específicas para a aplicação Railscasts e não há nenhuma maneira onde nós poderíamos cobrir tudo o que é necessário para atualizar qualquer aplicação para o Rails 3. Se você tiver avisos de código obsoleto ou mensagens de erro, então há chances de que alguém já tenha tido o mesmo problema e uma pesquisa no Google trará a uma solução. Também vale a pena conferir os outros episódios que abrangem Rails 3.
Um grande número de problemas que você vai encontrar quando atualizar uma aplicação será causado por plugins. O site Rails Plugins9 tem uma grande lista de plugins e diz se são compatíveis com o Rails 3 ou não. Se você tiver problemas com um plugin específico, também vale a pena verificar o repositório no Github para ver se há uma versão compatível com Rails 3 disponível.