#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.rb
Antes 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:2
Esse 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.