Rails 4 no Heroku

Heroku and Ruby on Rails

Rails 4 está chegando e é interessante verificar se vai dar muita dor de cabeça para migrar sua aplicação atual.
Para isso, seguem alguns problemas comuns que podem acontecer no momento do deploy e as soluções para os mesmos. No Heroku, a stack a ser utilizada deve ser a stack Cedar. Caso sua aplicação esteja nas stacks anteriores, será necessário criar uma nova aplicação utilizando esta stack.

O primeiro ponto que vamos atacar é a configuração para guardar a session no Rails. Esta configuração serve para quem utiliza cookie como forma de armazenamento e quer continuar utilizando. Na versão 4.0.0.beta1 ela possibilitava que o armazenamento fosse feito de forma encriptada através de uma opção no arquivo config/initializers/session_store.rb cadastrada da seguinte maneira:

config.session_store :encrypted_cookie_store

Na versão 4.0.0.rc1 do Rails esta característica passa a ser um comportamento padrão, conforme descrito no changelog e a única opção mantida foi:

config.session_store :cookie_store

Caso o arquivo esteja com a opção antiga, no momento do startup do servidor o Rails já vai acusar um erro, como o abaixo:

/Users/joviane/.rvm/gems/ruby-1.9.3-p392/bundler/gems/rails-04d27153fcef/railties/lib/rails/application/configuration.rb:144:in `const_get': uninitialized constant ActionDispatch::Session::EncryptedCookieStore (NameError)

Esse é um ponto que se deve ter cuidado. Caso você venha do Rails 3 direto, basta fazer do último jeito caso venha da beta do Rails 4, lembre-se de alterar novamente.

Outra mudança que veio com o Rails 4 foi a localização dos comandos para subir o servidor, criar projetos novos, executar as tasks, etc… Agora todos eles ficam dentro da pasta bin/ do seu projeto Rails. Apenas essa alteração não impacta em nada na nossa vida, já que quando você fizer bundle install, e estiver usando o Rails 4, os arquivos já serão gerados no lugar certo.

O problema é que se você tiver utilizando o binstubs do Bundler, o conteúdo também será gerado dentro do diretório /bin e com isso vai sobrescrever alguns dos comandos, que passaram a funcionar de maneira errada pois o Rails verifica se o conteúdo do script/rails é o mesmo do bin/rails. Como o conteúdo é diferente, o Rails sempre mostrará o help do novo comando. Por exemplo, caso você tente fazer rails s vai aparecer o help do rails new.
Esta situação inclusive está comentado numa issue lá no próprio Bundler.

Além disso, dependendo da task que você quer executar, pode aparecer uma mensagem indicando que não foi encontrado o railties nas suas gems:

/app/vendor/ruby-1.9.3/lib/ruby/1.9.1/rubygems/dependency.rb:247:in `to_specs': Could not find railties amongst [...] (Gem::LoadError)

Para resolver estes problemas, basta que após a instalação do Rails 4 seja executado o comando bundle config --delete bin para que o Bundler deixe de gerar os stubs e o comando rake rails:update:bin para que o Rails atualize os arquivos e os deixe funcionando da maneira correta. A saída do console será parecida com:

exist  bin
identical  bin/bundle
conflict  bin/rails
Overwrite /Users/joviane/caelum/test/project/bin/rails? (enter "h" for help) [Ynaqdh] a
force  bin/rails
conflict  bin/rake
force  bin/rake

A nova versão do Rails, já mostra inclusive uma mensagem comentando que deve ser atualizado o bin:

Looks like your app's ./bin/rails is a stub that was generated by Bundler.

In Rails 4, your app's bin/ directory contains executables that are versioned
like any other source code, rather than stubs that are generated on demand.

Here's how to upgrade:

  bundle config --delete bin    # Turn off Bundler's stub generator
  rake rails:update:bin         # Use the new Rails 4 executables
  git add bin                   # Add bin/ to source control

You may need to remove bin/ from your .gitignore as well.

When you install a gem whose executable you want to use in your app,
generate it and add it to source control:

  bundle binstubs some-gem-name
  git add bin/new-executable

O diretório /bin atualizado deve ser commitado e somente depois deve ser feito o push para o Heroku. Com os comandos gerados, os comandos do Rails são executados normalmente.

Hora de fazer o deploy. Ao tentarmos efetuá-lo utilizando o Rails 4, o Bundler do Heroku irá acusar que existem erros na instalação como a mensagem abaixo:

remote:        Gem::InstallError: activesupport requires Ruby version >= 1.9.3.
remote:        An error occurred while installing activesupport (4.0.0.beta1), and Bundler
remote:        cannot continue.
remote:        Make sure that `gem install activesupport -v '4.0.0.beta1'` succeeds before
remote:        bundling.
remote:  !
remote:  !     Failed to install gems via Bundler.
remote:  !
remote:  !     Heroku push rejected, failed to compile Ruby/rails app

Isto acontece pois o Rails 4 requer pelo menos a versão 1.9.3 do Ruby, sendo a versão 2.0.0 a recomendada. Porém, atualmente o Heroku utiliza por padrão a versão 1.9.2 do Ruby. Para que o deploy consiga ser efetuado, é necessário especificar no Gemfile a versão do Ruby que deve ser utilizada, por exemplo:

ruby "1.9.3"

Agora o deploy funcionou, mas ao executarmos a aplicação, vemos que o css e o js não estão sendo carregados. Se olharmos no log do Heroku, vemos que os arquivos com os assets não estão sendo encontrados:

ActionController::RoutingError (No route matches [GET] "/assets/application-a802b6f76dc4b7e26213ed231e5c407d.css")
ActionController::RoutingError (No route matches [GET] "/assets/application-75a7854682675193d462515d38e028bc.js")

Este problema se deve ao fato de que no Rails 3, o Heroku injetava como plugin no momento do deploy as funcionalidades para servir assets estáticos e efetuar log da aplicação. Como no Rails 4 foi removido o sistema de plugins, o Heroku disponibilizou duas gems que devem ser inseridas no Gemfile para habilitar o comportamento antigo:

gem 'rails_log_stdout', github: 'heroku/rails_log_stdout'
gem 'rails3_serve_static_assets', github: 'heroku/rails3_serve_static_assets'

Pronto, depois de realizada essas alterações tudo deve funcionar normalmente. Boa parte desses problemas foram passados durante a migração do Agendatech para a nova versão do Rails. E você já está pensando em migrar sua aplicação? Passou por algum outro problema? Não deixe de comentar aqui no blog.

6 Comentários

  1. Caio Ribeiro Pereira 13/05/2013 at 10:19 #

    Pelo visto Rails 4 promete! E é engraçado o Heroku que é um PAAS 100% Ruby não ter automatizado seu processo de deploy para ele.
    Thanks for this post! 🙂

  2. Nykolas Laurentino de Lima 13/05/2013 at 15:46 #

    Só não gostei dessa gem do heroku sendo configurada dentro da aplicação, faz a gente ter que vincular a aplicação a algo especifico para rode no heroku, quando a aplicação não deveria saber disso. Seria melhor se o Heroku tivesse uma forma de se virar com o Assets sem a gem, pra aplicação tanto faz como ele serve os arquivos do Asset, desde que ele sirva.

    Parabéns pelo post!

  3. David Bueno 26/08/2013 at 17:04 #

    Joviane vc sabe me diizer como resolver esse erro de deploy o heroku, depois de subir a aplicacao ela na roda, e no console do rails mostra a seguinte mensagem, eu ate tentei instalar a duas gens que vc disse no tutorial, mas na hora de fazer o deploy o heroku nao aceita

    Running `rails console` attached to terminal… up, run.7346
    DEPRECATION WARNING: You have Rails 2.3-style plugins in vendor/plugins! Support for these plugins will be removed in Rails 4.0. Move them out and bundle them in your Gemfile, or fold them in to your app as lib/myplugin/* and config/initializers/myplugin.rb. See the release notes for more on this: http://weblog.rubyonrails.org/2012/1/4/rails-3-2-0-rc2-has-been-released. (called from at /app/config/environment.rb:5)
    DEPRECATION WARNING: You have Rails 2.3-style plugins in vendor/plugins! Support for these plugins will be removed in Rails 4.0. Move them out and bundle them in your Gemfile, or fold them in to your app as lib/myplugin/* and config/initializers/myplugin.rb. See the release notes for more on this: http://weblog.rubyonrails.org/2012/1/4/rails-3-2-0-rc2-has-been-released. (called from at /app/config/environment.rb:5)
    DEPRECATION WARNING: You have Rails 2.3-style plugins in vendor/plugins! Support for these plugins will be removed in Rails 4.0. Move them out and bundle them in your Gemfile, or fold them in to your app as lib/myplugin/* and config/initializers/myplugin.rb. See the release notes for more on this: http://weblog.rubyonrails.org/2012/1/4/rails-3-2-0-rc2-has-been-released. (called from at /app/config/environment.rb:5)
    Loading production environment (Rails 3.2.13)
    irb(main):001:0>

  4. Joviane Jardim 26/08/2013 at 17:16 #

    David,

    Estes erros que estão aparecendo no console se devem ao fato de você ter plugins no diretório vendor/plugins. A partir do Rails 3 é recomendado que ao invés de plugins, você utilize apenas gems e no Rails 4 os plugins morreram de vez.
    Tenta achar uma gem que tenha a mesma funcionalidade que os plugins que você utiliza atualmente e assim você conseguirá migrar sua aplicação. Caso você não encontre uma gem compatível, você ainda pode colocar seus plugins dentro do diretório lib e criar um arquivo de inicialização para o Rails carregá-lo juntamente com a aplicação.
    Lembre que estas mensagens são só avisos, não vai impactar no uso da sua aplicação enquanto você não efetuar a atualização para o Rails 4.

  5. David Bueno 26/08/2013 at 17:37 #

    Ok Joviane
    porem minha apicacao nao tem nenhum plugin, so mesmo os diretorios vazios, so que mesmo assim a aplicacao ainda nao roda poderia ser um outro erro??????

  6. Joviane Jardim 26/08/2013 at 20:45 #

    David,

    Vou te mandar um e-mail para poder te ajudar. 😀

Deixe uma resposta