Al's blog

Alexis Toulotte

10 juil 07

Fixtures on Rails

Il est assez fréquent d’avoir du contenu à pré-remplir dans une base de données lors du déploiement d’une application.

La plupart du temps on se fait un script SQL qui fait les insertions. En Rails, c’est mieux, on mets les insertions dans les scripts de migration et ça roule.

Petit hic, mettons que l’on a beaucoup de données et contenant des champs text, le script de migration va vite devenir illisible. Pour ça il y a les Fixtures. Seulement, ce n’est pas géré par les migrations (de base). Les fixtures sont représentés grâce à des fichiers YAML décrivant vos modèles.

Voilà un petit script à rajouter dans le répertoire /lib/ (nommez-le create_fixtures.rb) :

require 'active_record/fixtures'
 
module CreateFixtures
 
  FIXTURES_LOCATION = 'db/fixtures'
 
  def self.extended(object)
    class << object
      alias_method :migrate_without_fixtures, :migrate unless method_defined?(:migrate_without_fixtures)
      alias_method :migrate, :migrate_with_fixtures
    end
  end
 
  def migrate_with_fixtures(direction)
    migrate_without_fixtures(direction)
    return if :down == direction
    version = ActiveRecord::Migrator.current_version + 1
    cnx = ActiveRecord::Base.connection
    files = Dir["#{FIXTURES_LOCATION}/[0-9]*_*.yml"].each do |file|
      next unless file.gsub(/.*/([0-9]+)_.*.yml/, '1').to_i == version
      table_name = file.gsub(/.*/[0-9]+_(.*).yml/, '1')
      Fixtures.new(cnx, table_name, nil, file.gsub(/(.*).yml/, '1')).insert_fixtures
    end
  end
 
end
 
ActiveRecord::Migration.extend(CreateFixtures)

Ensuite, rajouter cette ligne dans le fichier config/environment.rb :

require File.dirname(__FILE__) + '/../lib/create_fixtures'

Voilà la chose est en place. Maintenant voyons l’utilisation.

Vous avez juste à créer un répertoire db/fixtures dans votre application et y mettre vos fichiersYAML. Nommez vos fichiers de la sorte :

<numéro_de_migration><nom_de_la_table>.yml

Rien de mieux qu’un petit exemple :

$ cat db/fixtures/002_users.yml
login: admin
hashed_password: d033e22ae348aeb5660fc2140aec35850c4da997
status: administrator

Ici, l’utilisateur administrateur sera directement ajouté à la fin de la deuxième migration. Vous pouvez bien-entendu mettre plusieurs fichiers de fixtures pour une même migration et créer des utilisateurs par exemple après la deuxième ou même la 42e migration.

4 commentaires sur « Fixtures on Rails »

  1. shingara dit :

    Et pourquoi ne pas utiliser tout simplement la tâche rake :

    rake db:fixtures:load

    qui permet de loader toutes les fixtures des tests dans ta Base de donnée. Ainsi avec seulement un jeu de donnée, tu peux les utiliser avec tes test et avec ton remplissage initiale de base de donnée.

  2. al dit :

    Pour certaines raisons. D’une ces fixtures (de test) ne seront pas synchrones avec tes migrations. Mettons que tu ais une version en prod et qu’ensuite tu veuilles rajouter des fixtures depuis ton trunk dev. Avec db:fixtures:load, il va tout te charger, et en plus depuis les fixtures de test, ce qui n’est pas forcement ce que tu veux dans tes futures bases.

    De plus, la méthode ci-dessus te permet de garder un « historique » entre la version dev a la version prod.

    Après, tout dépend des besoins. Tes données peuvent évoluer coté prod et parfois tu ne veux pas y toucher lors de la migration de ta base.

  3. martin dit :

    shingara: le problème vient justement du fait que la tache rake va loader toutes les fixtures.

    Lorsque tu passes en prod initialement, pas de problème, tu charges tout mais lorsque l’appli est déjà en prod et que tu fais une évo tu ne peux pas te permettre de reloader toutes les fixtures puisque tes données ont sûrement évoluées de leur coté.

    L’idée c’est donc d’avoir un jeu de données liée à une certaine migration.

  4. [...] à mon précédent billet concernant la création d’un jeu de données propre à une migration en utilisant les [...]

Laisser un commentaire