Comprenez et améliorez le cache statique des applications Rails

Le framework de développement offre, depuis sa toute première version, la possibilité de mettre en cache tout ou partie d'une page Web. Le point sur cette technique.

Le framework de développement Web Ruby on Rails offre, depuis sa toute première version, la possibilité de mettre en cache tout ou partie d'une page. Cela va du cache de fragments de page à la création d'un bon vieux fichier HTML statique.

Pour les sites dont le contenu reste relativement stable, cette dernière méthode est particulièrement puissante : en effet, une fois votre cache généré, Apache, votre serveur Web favori pourra y accéder directement sans faire appel à votre application Rails. Vous y gagnerez ainsi largement en termes de performance et d'économie de ressources.
 

Comment fonctionne le cache statique


Comment fonctionne le cache statique ? Plutôt bien, ma foi, mais ce n'est pas le sujet.

Chaque fois qu'un navigateur va vouloir accéder à une page, votre serveur Web va vérifier son existence sur le système de fichier.

 Si la page existe, elle sera directement envoyée au navigateur.
 Si elle n'existe pas, le serveur Web passe la main à votre application Rails qui génère la page, l'envoie au navigateur, et en profite pour la sauvegarder sur votre système de fichiers.

Tout ceci est fourni par le module ActionController::Caching::Pages, qui vous propose trois méthodes : cache_page, caches_page et expire_page. Vous utiliserez le plus souvent la seconde. Pour la cuisine interne, je vous invite à lire les sources des méthodes, mais en gros, Rails crée l'arborescence de répertoires nécessaire, puis dépose le fichier à l'intérieur, ce n'est pas plus difficile que ça.

 

Changer le répertoire de stockage du cache statique


Par défaut, Rails stocke le cache statique dans le répertoire public, qui se trouve également être le DocumentRoot de votre hôte virtuel sous Apache. Ainsi, pas besoin de faire appel à mod_rewrite pour aller chercher le cache, les fichiers sont accessibles directement.

Conditionner la génération du cache à la présence d'une query string vide

Malheureusement, cela signifie également que votre cache – éphémère – partage le même espace que vos fichiers statiques, par essence beaucoup plus pérennes. C'est loin d'être pratique, et vous risquez d'effacer quelque chose par mégarde.

Qu'à cela ne tienne, vous allez mettre votre cache à part, ce qui sera à la fois beaucoup plus pratique et beaucoup plus sûre.

Dans le fichier config/environment.rb, ajoutez la ligne suivante : 

 config.action_controller.page_cache_directory 
 = "#{RAILS_ROOT}/public/cache/"

Dans le fichier de configuration de votre hôte virtuel, ajoutez les lignes suivantes au début des règles de réécriture :

RewriteEngine On
















RewriteCond %{DOCUMENT_ROOT}/cache/%{REQUEST_FILENAME} -f
RewriteRule ^/(.*)$ /cache/$1 [PT]


Redémarrez Apache. Si vous n'utilisez pas Apache, adaptez ou changez de serveur Web. Mod_rails est vraiment bien, et Apache est aussi léger que puissant quand on sait s'en servir.

 

En finir avec les pages qui renvoient du XML au lieu du HTML


Rails a un petit soucis de comportement. L'extension des pages se fait en fonction de celle du nom de fichier appelé. Le système de routage décide alors du format à utiliser, et le controller gère. Rien de plus simple :

 index.html : on renvoie du HTML et on génère un fichier .html (comportement par défaut).
 index.rss : on renvoie du RSS et on génère un fichier .rss.
 index.atom : on renvoie de l'Atom et on génère un fichier .atom.

Jusque là, rien d'anormal c'est le comportement attendu.

Là où les choses se gâtent, c'est qu'il existe un second moyen d'indiquer à Rails le format souhaité : en initialisant la variable format dans la query string. Ainsi, au lieu de http://toto.com/index.rss, on peut appeler http://toto.com/index?format=rss.

 

Normalement, cela ne doit pas arriver, sauf dans deux cas :

  1. Votre application a été mal codée, et il vous manque des routes.
  2. Votre application utilise une très très ancienne version de Rails, ou l'a fait, et ces appels existent toujours – ils sont valides – dans la mémoire des moteurs de recherche.

Que se passe-t-il ? Le générateur de pages statiques ne voyant pas arriver d'extension, il considère qu'il sert du HTML (comportement par défaut). Il va donc sauvegarder un fichier au format HTML, mais dont le contenu sera au format RSS.
Comment l'éviter ? On va conditionner la génération du cache à la présence d'une query string vide. Ainsi, dans votre application,

 caches_page :index

devient :

 caches_page :index, :if => Proc.new {|c| 
 c.request.query_string == ''
 }


C'est tout ? Ben oui, c'est tout ! Et c'est déjà pas mal.

Tutoriel réalisé par Frédéric de Villamil sous licence Creative Commons