14Ago08 Novo no Rails Edge: Suporte simples a “Conditional-Get” (ETags)
O Carlos Brando vem fazendo um excelente trabalho em trazer para nós as novidades do Rails Edge (no caso, o 2.2). Mas ao me deparar com esta atualização não pude me conter em blogar sobre. Na verdade, apenas traduzir o artigo do Ryan.
———–
Conditional-gets são uma facilidade da especificação do HTTP que fornece um método de os servidores we comunicarem aos brosers que a resposta para a requisição GET não mudou desde a última requisição e que o cache do browser pode ser usado com segurança.
Eles funcionam usando os cabeçalhos HTTP_IF_NONE_MATCH e HTTP_IF_MODIFIED_SINCE para passar para frente e para trás um identificador único do conteúdo e o timestamp de quando o conteúdo foi modificado pela última vez. Se o browser fizer a requisição onde o identificador do conteúdo (etag) ou a data da última modificação bater com a versão do servidor então o servidor precisa apenas enviar de volta uma resposta vazia com um status de “não modificado” (304).
É do servidor (nós) a responsabilidade de olhar a data da última modificação e o cabeçalho if-none-match e determinar quando ou não enviar a resposta completa (com a renderização da página, por exemplo). Com este novo suporte a conditional-get no rails, isto se torna uma tarefa muito fácil:
class ArticlesController < ApplicationController
def show
 @article = Article.find(params[:id])
# Define o cabeçalho da resposta para refletir exatamente
# o estado do objeto requisitado
 response.last_modified = @article.published_at.utc
 response.etag = @article
# Se o estado da requisição é o mesmo do estado no servidor
 # então sabemos que não precisamos enviar todo o resultado
 if request.fresh?(response)
 head :not_modified
 else
 respond_to do |wants|
# normal response processing
 end
 end
end
end
O valor do etag é calculado para você com o metodo setter etag=. Tudo que você tem que fazer é prover um único objeto ou array de objetos que definem de forma única a identificação desta requisição. Neste exemplo o artigo por si mesmo contém toda a informação que identifica o estado desta requisição. De qualquer forma, você pode precisar de usar mais de uma chave em seu aplicativo. Como para uma requisição especÃfica para cada usuário:
response.etag = [@article, current_user]
O método request.fresh?(response) é quem dirá a você se a requisição casa com o valor de last-modified-since ou if-none-match da resposta que está sendo enviada. Se sim, você pode evitar de responder todo o conteúdo e economizar alguma (ou muita!) banda.
Também é possÃvel você evitar de acessar o banco de dados se seu aplicativo trata com páginas completamente estáticas armazenadas no banco de dados (isso é raro):
class ArticlesController < ApplicationController
def show
# Se o artigo não muda, o etag pode se basear apenas em
 # Ãtems que temos na requisição
 response.etag = [:article, params[:id]]
# Se o estado da requisição é o mesmo do servidor
 # podemos evitar também de acessar o banco de dados
 if request.fresh?(response)
 head :not_modified
 else
 @article = Article.find(params[:id])
 respond_to do |wants|
 ...
 end
end
 end
end
Então, seja um bom cidadão e faça suas requisições compatÃveis com conditional-get. Isto é a coisa certa a ser feita - e melhoram também a performance de seus programas.
—-
Vale notar, que você pode também usar estes cabeçalhos para acessar webservices (principalmente os feitos em Rails agora :D) fazendo requisição de XML, se você, por exemplo, estiver guardando os dados que você acessou e guardar a data em que isto foi feito, assim você economisa ainda mais banda!
tags {edge, rubyonrails}





