Rails: Páginas de manutenção com Capistrano
Já tem um tempinho que quero falar sobre Capistrano em um material mais completo, o problema é que ando muito ocupado então só sobrou tempo para pequenas dicas.
Na semana passada capistrano 2.5 foi lançado e Jamis Buck anúncio que não será mais o mantenedor deste projeto que praticamente se tornou a forma padrão de colocar sistemas e websites Rails online. Nem por isso o projeto está morto e você precisa achar que deve encontrar outra ferramenta, por ser OpenSource e no github já temos gente a frente do projeto para continuar o trabalho de Jamis.
A dica de hoje será sobre as formas de utilizar uma feature muito bacana do Capistrano, cap deploy:web:disable. Em várias situações você vai precisar tirar do ar seu sistema ou website e não é interessante ter nenhum outro link acessível, só remover a index não resolve pois pode gerar problemas enormes se um cliente acessar o sistema quando ele estiver em manutenção e depois perder os dados.
Para isso o Capistrano tem o comando que pode ser chamado pelo terminal cap deploy:web:disable que gera um página maintenance.html e a copia para a public do seu projeto. Mas o Capistrano não pode fazer mágica, seu servidor web precisa saber que caso existe esta página ele deve rotear todas as requisições para esta página.
Então vamos ao passo a passo, considerando que você já está com sua receita capistrano configurada devidadamente e o deploy do seu projeto é feito com Capistrano mas um cliente te liga e manda tirar o site do ar por alguns dias, você vai ao terminal e digita:
macbook:meu_projeto daniellopes$ cap:deploy:web:disable
Agora na pasta shared/system do seu projeto Rails no seu host terá uma arquivo de manutenção com o conteúdo semelhante a imagem abaixo:

Agora você precisa avisar a seu webserver para rotear tudo para a maintenance.html quando a página existir. Vamos usar Apache, abra o .htacess do seu projeto e então:
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]
Usamos as regras acima pois o Capistrano por padrão cria o arquivo maintenance na pasta compartilhada system dentro da shared no seu servidor. Feito isto tudo já deve estar funcionando e ao acessar a url do projeto você verá uma tela de manutenção.
Mas nós somos brasileiros e precisamos traduzir a coisa. Abra o arquivo deploy.rb dentro da pasta config do seu projeto e então reescreva a task disable, como abaixo:
namespace :deploy do
namespace :web do
task :disable, :roles => :web do
on_rollback { rm "#{shared_path}/system/maintenance.html" }
require 'erb'
deadline, reason = ENV['UNTIL'], ENV['REASON']
maintenance = ERB.new(File.read("./app/views/layouts/maintenance.html.erb")).result(binding)
put maintenance, "#{shared_path}/system/maintenance.html", :mode => 0644
end
end
end
O que estamos fazendo acima é dizer que agora a task disable ( que está dentro dos namespaces web e deploy ) irá gerar o maintenance.html com base em um arquivo maintenance.html.erb dentro da pasta layout do nosso projeto. Desta forma podemos criar um arquivo erb com o nosso layout além de traduzido.
Também repare que temos duas variáveis, na linha:
deadline, reason = ENV['UNTIL'], ENV['REASON']
Por padrão a task deploy:web:disable aceita duas variáveis de ambiente, UNTIL e REASON que é o horário e o motivo do site estar off-line. Entendido isso, podemos fazer nosso template:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Site em manutenção</title>
<style type="text/css">
div.outer {
position: absolute;
left: 50%;
top: 50%;
width: 500px;
height: 300px;
margin-left: -260px;
margin-top: -150px;
}
.DialogBody {
margin: 0;
padding: 10px;
text-align: left;
border: 1px solid #ccc;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
background-color: #fff;
}
body { background-color: #fff; }
</style>
</head>
<body>
<div class="outer">
<div class="DialogBody" style="text-align: center;">
<div style="text-align: center; width: 200px; margin: 0 auto;">
<p style="color: red; font-size: 16px; line-height: 20px;">
Este website está fora do ar <%= reason ? reason : "maintenance" %>
a partir de <%= Time.now.strftime("%H:%M %Z") %>.
</p>
<p style="color: #666;">
Nós voltaremos <%= deadline ? deadline : "o quanto antes possível" %>.
</p>
</div>
</div>
</div>
</body>
</html>
Agora basta executar:
macbook:meu_projeto daniellopes$ cap:deploy:web:disable REASON="atualizando o estoque" UNTIL="15:00"
E quando estiver tudo ok com o sistema basta fazer o inverson:
macbook:meu_projeto daniellopes$ cap:deploy:web:enable
Simples, não? Agora temos nossa tela de manutenção personalizada e traduzida. Também seria possível utilizar a API de internacionalização do Rails mas como é uma tarefa razoavelmente simples não vou explicar aqui.