Fixtures on Rails
Par al le mar, 10 juil 2007, 16:40 - Geekeries - Lien permanent
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
admin:
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.
Commentaires
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.
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.
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.