#225 Upgrading to Rails 3 Part 1
O primeiro release candidate do Rails 3.0 já foi lançado. Esse é um ótimo momento para experimentar o Rails 3, se você já não tiver feito isso, e para ver quais mudanças precisam ser feitas em suas aplicações Rails 2 para atualizá-las. Neste episódio vamos mostrar como atualizar uma aplicação Rails 2.3 para Rails 3.0.
Já existe uma série de episódios sobre Rails 3.0 que você pode assistir ou ler e nós vamos fazer referências a alguns episódios relevantes enquanto trabalhamos com a atualização. A aplicação que vamos começar a atualizar é o site railscasts.com. O código fonte está disponível no Github.
Mesmo se você não estiver pronto para usar Rails 3 em produção, ainda vale a pena tentar atualizar as aplicações Rails 2 só para ver quais problemas você terá que enfrentar. Se suas aplicações usam Git para controle de versão, é fácil criar um branch separado para experimentar. Vamos criar um novo branch chamado rails3.
$ git checkout -b rails3 Switched to a new branch 'rails3'
Antes de começarmos a atualização
Antes de atualizar uma aplicação para o Rails 3, devemos atualizá-la para a última versão do Rails 2.3, que no momento é o Rails 2.3.8. Da mesma forma, qualquer gem que a aplicação usa, deve ser atualizada para a versão mais recente. Desta forma, vamos garantir que não existem problemas de compatibilidade com as versões mais recentes.
Uma vez que tenhamos atualizado o Rails e as gems, devemos executar nossos testes. Ter uma boa suíte de testes automatizados ajudará a garantir que tudo ainda está funcionando como deveria.
$ rake spec (in /Users/eifion/rails/apps_for_asciicasts/ep225/railscasts) DEPRECATION WARNING: Rake tasks in vendor/plugins/hoptoad_notifier/tasks ........................................................................................................................................................ 152 examples, 0 failures
Todos os testes passaram. Então estamos prontos para a atualização.
Atualizando o Ruby e Instalando o Rails 3
Para a atualização, queremos utilizar a última versão do Ruby em um ambiente limpo para a aplicação Rails 3, por isso vamos usar o rvm para instalar a última versão do Ruby 1.9.2 e instalar o Rails 3.0. O rvm é atualizado frequentemente, por isso vamos garantir que temos a versão mais recente executando update rvm antes de instalar o Ruby.
$ rvm update rvm 0.1.40 by Wayne E. Seguin (wayneeseguin@gmail.com) [http://rvm.beginrescueend.com/] info: fetching rvm-0.1.43.tar.gz info: Extracting rvm-0.1.43.tar.gz ... info: Installing rvm-0.1.43...
Uma vez que o rvm está atualizado, precisamos recarregá-lo. Podemos fazer isso, executando:
$ rvm reload
Agora podemos usar o rvm para instalar o Ruby 1.9.2.
$ rvm install 1.9.2
Esse comando irá baixar, compilar e instalar a última versão do Ruby 1.9.2, atualmente em rc2. Quando estiver concluído (pode demorar alguns minutos) poderemos mudar para a nova versão e verificar se ela funciona.
$ rvm 1.9.2 $ ruby -v ruby 1.9.2dev (2010-07-11 revision 28618) [x86_64-darwin10.4.0]
Agora que sabemos que estamos rodando a versão correta do Ruby, podemos instalar a gem do Rails 3.0 release candidate.
gem install rails --pre
Note que como estamos usando uma versão do Ruby instalada com rvm, não precisamos usar sudo para instalar gems.
Começando a atualização
Agora temos uma nova instalação do Ruby e o Rails 3.0. Então estamos prontos para começar a atualizar nossa aplicação. Para nos ajudar, temos o rails_upgrade plugin, que é um plugin oficial que podemos usar para ver quais alterações precisamos fazer. Para instalar o rails_upgrade, primeiro precisamos voltar para o Rails 2, que está instalado no ambiente do Ruby do sistema.
$ rvm system
Agora podemos instalar o plugin.
$ script/plugin install git://github.com/rails/rails_upgrade.git
Será apresentada uma documentação útil depois da instalação. Um dos principais comandos que ele acrescenta é o rake rails:upgrade:check. Quando executamos esse comando no diretório da nossa aplicação, ele irá mostrar uma lista de tudo que precisa ser atualizado em nossa aplicação. A saída é muito longa para mostrar aqui, mas como exemplo, veremos a primeira parte.
$ rake rails:upgrade:check
(in /Users/eifion/rails/apps_for_asciicasts/ep225/railscasts)
Old router API
The router API has totally changed.
More information: http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/
The culprits:
- config/routes.rbAntes de começarmos a atualização, vamos executar rake rails:upgrade:backup. Isso irá fazer backup de alguns dos principais arquivos que são suscetíveis de alteração durante a atualização.
$ rake rails:upgrade:backup (in /Users/eifion/rails/apps_for_asciicasts/ep225/railscasts) DEPRECATION WARNING: Rake tasks in vendor/plugins/hoptoad_notifier/tasks are deprecated. Use lib/tasks instead. (called from /Library/Ruby/Gems/1.8/gems/rails-2.3.8/lib/tasks/rails.rb:10) * backing up .gitignore to .gitignore.rails2 * backing up app/controllers/application_controller.rb to app/controllers/application_controller.rb.rails2 * backing up app/helpers/application_helper.rb to app/helpers/application_helper.rb.rails2 * backing up config/routes.rb to config/routes.rb.rails2 * backing up config/environment.rb to config/environment.rb.rails2 * backing up config/environments/development.rb to config/environments/development.rb.rails2 * backing up config/environments/production.rb to config/environments/production.rb.rails2 * backing up config/database.yml to config/database.yml.rails2 This is a list of the files analyzed and backed up (if they existed); you will probably not want the generator to replace them since you probably modified them (but now they're safe if you accidentally do!). - .gitignore - app/controllers/application_controller.rb - app/helpers/application_helper.rb - config/routes.rb - config/environment.rb - config/environments/development.rb - config/environments/production.rb - config/environments/staging.rb - config/database.yml - config.ru - doc/README_FOR_APP - test/test_helper.rb
Começaremos a atualizar criando uma nova aplicação Rails 3 no diretório da aplicação. Para fazer isso, é necessário voltar ao ambiente do Ruby 1.9.2.
$ rvm 1.9.2
Agora podemos criar a nova aplicação Rails 3 com:
$ rails new .
Como estamos criando uma nova aplicação no mesmo diretório de uma existente, seremos questionados sobre sobrescrever alguns arquivos existentes. Se não temos certeza se o arquivo deve ser sobrescrito, podemos usar a opção d para ver as diferenças entre o arquivo existente e o que vai sobrescrever.
Nós fizemos backup dos arquivos mais importantes e podemos sobrescrever todos os arquivos conflitantes, exceto esses:
/README/app/views/layouts/application.html.erb/public/javascripts/application.js
Os outros arquivos, ou não tiveram mudanças, ou têm backup, nos permitindo refazer quaisquer alterações na nova versão a medida que avançamos.
Nossa aplicação está agora atualizada para o Rails 3.0, mas ainda temos que percorrer os arquivos que fizemos backup e copiar qualquer código que seja específico da nossa aplicação. Cada arquivo que foi feito backup, está em seu diretório original com uma extensão .rails2. Então só precisamos abrir cada arquivo de backup, juntamente com a nova versão, e copiar os códigos que precisam ser mantidos.
Vamos começar com o arquivo de rotas. A sintaxe das rotos mudou, mas a antiga ainda funciona no Rails 3, embora esteja obsoleta (deprecated). Nesse momento podemos apenas copiar as rotas do arquivo de backup para o novo arquivo de rotas e vamos testar isso depois.
Em seguida vamos dar uma olhada no arquivo /config/environment.rb. Corrigir esse arquivo vai dar um pouco mais de trabalho, pois a configuração mudou bastante no Rails 3. O arquivo padrão dos ambientes está bem menor pois as opções de configuração não estão mais lá, foram para o arquivo /config/application.rb.
Existem três coisas no backup do environment.rb que precisamos considerar. A primeira é a configuração do time zone.
config.time_zone = 'Pacific Time (US & Canada)'
Essa linha pode ser movida para o arquivo /config/application.rb.
A segunda parte é o código da sessão.
config.action_controller.session = {
:session_key => APP_CONFIG['session_key'],
:secret => APP_CONFIG['session_secret']
}No Rails 3 esse código pertence a um arquivo initializer e se olharmos esse arquivo, vamos ver o código para configurar os dados de sessão da aplicação.
# Be sure to restart your server when you modify this file. Railscasts::Application.config.session_store :cookie_store, :key => '_railscasts_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rake db:sessions:create") # Railscasts::Application.config.session_store :active_record_store
Podemos deixar esse código como está por enquanto. Vamos alterar isso depois, mas isso não será necessário para ter o site instalado e funcionando.
Finalmente, no final do arquivo de backup do environment.rb está o código de configuração das gems da aplicação.
config.gem "RedCloth", :lib => 'redcloth', :version => ">= 4.0" config.gem "coderay" config.gem 'acts-as-list' config.gem 'will_paginate' config.gem 'thinking-sphinx', :lib => 'thinking_sphinx' config.gem 'whenever', :lib => false
Esse código pode ser copiado para o Gemfile, que está no diretório raiz da aplicação. A sintaxe foi ligeiramente modificada e o código precisa ser alterado assim:
gem "RedCloth", ">=4.0", :require => 'redcloth' gem "coderay" gem 'acts-as-list' gem 'will_paginate' gem 'thinking-sphinx', :require => 'thinking_sphinx' gem 'whenever', :require => false
Além de alterar o config.gem para gem em cada linha, há algumas outras alterações que precisamos fazer. O número da versão agora é passado como segundo parâmetro e a opção :lib foi renomeada para :required.
Feito isso, precisamos executar bundle install para ter certeza de que todas as gems necessárias estão instaladas. Para mais informações sobre o bundler e instalação de gems você pode assistir ou ler o episódio 201. Não vamos falar em copiar os códigos dos outros arquivos de backup, mas deve ser bastante simples transferir o código necessário do backup para o novo arquivo.
Com as gems instaladas, vamos tentar iniciar o servidor para ver se a aplicação será iniciada.
$ rails s /Users/eifion/.rvm/gems/ruby-1.8.7-p299/gems/will_paginate-2.3.14/lib/will_paginate.rb:39:in `enable_activerecord': undefined method `returning' for WillPaginate:Module (NoMethodError) # rest of error truncated…
Não foi. E o motivo foi um erro no código da gem will_paginate, onde temos um método returning indefinido. Esse método estava disponível no Rails 2, mas foi removido no Rails 3.
Em casos como esse, vale a pena chegar o site RubyGems para ver se há disponível uma nova versão da gem em prerelease compatível com o Rails 3. No caso do will_paginate existe e podemos usar, acrescentando o número da versão da gem em nosso Gemfile.
gem 'will_paginate', '>=3.0.pre'
Se executarmos bundle install novamente, a versão prerelease da gem será instalada e poderemos usar. Agora podemos tentar iniciar o servidor de novo.
$ rails s
/Users/eifion/.rvm/gems/ruby-1.8.7-p299/gems/after_commit-1.0.7/lib/after_commit/active_record.rb:15:in `include_after_commit_extensions': undefined method `subclasses_of' for Object:Class (NoMethodError)
from /Users/eifion/.rvm/gems/ruby-1.8.7-p299/gems/after_commit-1.0.7/lib/after_commit.rb:81
from /Users/eifion/.rvm/gems/ruby-1.8.7-p299/gems/thinking-sphinx-1.3.18/lib/thinking_sphinx.rb:2:in `require'
from /Users/eifion/.rvm/gems/ruby-1.8.7-p299/gems/thinking-sphinx-1.3.18/lib/thinking_sphinx.rb:2Esse erro parece ter sido causado pela gem Thinking Sphinx. Novamente há uma versão prerelease disponível que podemos usar. Então temos que fazer outra alteração no Gemfile e daí executar o bundle install de novo.
gem 'thinking-sphinx', '>=2.0.0.rc1', :require => 'thinking_sphinx'
Vamos tentar iniciar o servidor de novo.
$ rails s DEPRECATION WARNING: railtie_name is deprecated and has no effect. (called from <class:Railtie> at /Users/eifion/.rvm/gems/ruby-1.9.2-rc2/gems/will_paginate-3.0.pre/lib/will_paginate/railtie.rb:6) => Booting WEBrick => Rails 3.0.0.rc application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server Exiting /Users/eifion/rails/apps_for_asciicasts/ep225/railscasts/config/routes.rb:2:in `block in <top (required)>': undefined local variable or method `map' for #<ActionDispatch::Routing::Mapper:0x00000101dffde8> (NameError)
Dessa vez temos algo novo. O servidor tenta iniciar mas reclama sobre uma variável ou método indefinido chamado map nas rotas. Conforme nós colamos o antigo código das rotas no novo arquivo de rotas, estamos usando uma variável map, mas a variável não é passada para o bloco, pois ela não é obrigatória no Rails 3. Nós ainda podemos usar a antiga sintaxe de rotas e passar essa variável.
Railscasts::Application.routes.draw do |map| map.resources :spam_questions map.resources :spam_checks map.with_options :controller => 'info' do |info| info.about 'about', :action => 'about' info.contest 'contest', :action => 'contest' info.feeds 'feeds', :action => 'feeds' info.give_back 'give_back', :action => 'give_back' end map.login 'login', :controller => 'sessions', :action => 'new' map.logout 'logout', :controller => 'sessions', :action => 'destroy' map.resources :sponsors map.resources :comments map.resources :tags map.resources :episodes, :collection => { :archive => :get } map.resources :sessions map.resources :spam_reports, :member => { :confirm => :post }, :collection => { :confirm => :post } map.root :episodes end
Quando tentamos iniciar o servidor pela quarta vez, temos sorte e ele inicia sem erros.
$ rails s DEPRECATION WARNING: railtie_name is deprecated and has no effect. (called from <class:Railtie> at /Users/eifion/.rvm/gems/ruby-1.9.2-rc2/gems/will_paginate-3.0.pre/lib/will_paginate/railtie.rb:6) => Booting WEBrick => Rails 3.0.0.rc application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2010-08-05 19:30:22] INFO WEBrick 1.3.1 [2010-08-05 19:30:22] INFO ruby 1.9.2 (2010-07-11) [x86_64-darwin10.4.0] [2010-08-05 19:30:22] INFO WEBrick::HTTPServer#start: pid=9933 port=3000
Se visitarmos a página principal no navegador, vamos ver a página inicial padrão, pois ela foi recriada no diretório /public quando criamos a aplicação Rails 3. Podemos ver nessa página, que o ambiente correto está sendo usado.
Embora tenhamos iniciado o servidor com sucesso, ainda temos muitas coisas que precisamos corrigir, como vemos quando executamos rails:upgrade:check novamente. Também precisamos executar nossas specs de novo para ver se elas passam. Nós vamos fazer isso no próximo episódio.


