À mesure que les applications web à héberger se développent, disposer d’un installer automatisé devient de plus en plus souvent une étape obligatoire, là où elle n’était qu’un luxe il y a encore quelques mois. En aucun cas les utilisateurs ne devraient plonger les mains dans le code, pas même pour remplir les informations nécessaires à la connexion à une base de données. Les hébergeurs ne pouvant automatiser le déploiement de toutes les applications web existantes, il revient donc aux équipes de développement de simplifier l’installation de leur produit.

Si le setup de Wordpress peut être cité comme exemple de simplicité et de concision, les applications Rails ne sont heureusement pas en reste (mais bien en REST), et un installer, originellement développé pour Typo existe. On ne dispose malheureusement pas toujours de ce dernier, soit par manque d’accès SSH sur le serveur, soit parce que l’application ne le supporte pas, soit parce qu’elle utilise Rails 2.0 pour lequel l’installer n’a pas encore été mis à jour.

Dans le cadre du développement de Typo, je souhaitais mettre en place une telle procédure de setup distincte du Rails Installer, à destination des utilisateurs passant par les sources pour installer leur blog.

class Admin::BaseController < ApplicationController
before_filter :check_migration

...

  def check_migration
    begin
      ActiveRecord::Base.connection.select_all("select * from sessions")
    rescue
      redirect_to :controller => '/admin/general', :action => 'create_database' 
    end
  end

Le principe est – apparemment – simple. Lorsqu’on tente d’accéder à l’application, celle-ci tente une requête sur la table sessions. Si cette dernière n’existe pas, Rails déclenche une exception que mon controller intercepte afin de rediriger l’utilisateur vers la page setup. Cette dernière ne fait rien d’autre que lui proposer de créer et de peupler les tables à sa place, le formulaire n’étant là pour le rassurer en lui donnant l’impression d’être actif dans le processus.

Malheureusement, cela ne marche pas. Rails tente d’accéder à la table sessions – une table système – avant que l’application ne puisse prendre la main, et génère une exception que je ne peux donc pas intercepter. Il faut donc contourner le problème, et le seul endroit possible pour le faire est dans le fichier config/environment.rb.

  if RAILS_ENV != 'test'
    begin
      ActiveRecord::Base.connection.select_all("select * from sessions")
    rescue
      Migrator.migrate
    end
  end

Migrator est un module développé pour Typo qui permet tout simplement d’accéder plus facilement aux tâches de migration depuis une application.

module Migrator
  def self.migrate(version = nil)
    ActiveRecord::Migrator.migrate("#{migrations_path}/", version)
  end

...

Dans un premier temps, cette solution peut sembler particulièrement sale, dans le sens où environment.rb n’est pas vraiment fait pour ça. Elle présente pourtant un atout non négligeable. La vérification de la base se fait en effet une seule fois, au lancement du serveur d’application, et non pas à chaque appel à l’application. Malgré la présence d’un cache statique, on économise un nombre peu négligeables de requêtes SQL, ce qui n’est pas plus mal pour les performances. L’utilisateur n’a plus qu’une chose à faire, remplir son database.yml, et c’est tout. L’installation en est en tout cas grandement simplifiée.

Londres ? Non, Bordeaux !

Perry the Platypus wants you to subscribe now! Even if you don't visit my site on a regular basis, you can get the latest posts delivered to you for free via Email: