Frederic de Villamil


, , , , , , , ,


Partagez sur Twitter Partagez sur Facebook Partagez sur Google Plus Partagez sur Linkedin Plus

Comprenez et améliorez le cache statique de vos applications Rails

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 performances et d’économie de ressources.

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 3 méthodes : cachepage, cachespage 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 stock 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.

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. Non solum c’est le bordel sed etiam vous risquez d’effacer quelque chose par mégarde. Par exemple toutes les présentations S5 que j’ai faites ces 4 dernières années.

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

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

<typo:code lang=’ruby’> config.actioncontroller.pagecachedirectory = “#{RAILSROOT}/public/cache/” </typo:code>

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

<typo:code> RewriteEngine On

RewriteCond %{DOCUMENTROOT}/cache/%{REQUESTFILENAME} -f RewriteRule ^/(.*)$ /cache/$1 [PT] </typo:code>

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 qui m’a fait passer deux ou trois nuits blanches à l’époque où il affectait régulièrement ce site. 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 ? (un méchant ? où ça ?)

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,

<typo:code lang=’ruby’> caches_page :index </typo:code>

devient :

<typo:code lang=’ruby’> cachespage :index, :if => Proc.new {|c| c.request.querystring == ” } </typo:code>

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