2010-05-30 5 views
40

J'ai un modèle Foo qui has_many 'Bar'. J'ai une usine factory_girl pour chacun de ces objets. L'usine de Bar a une association avec Foo; il va instancier un Foo quand il crée la barre.Remplir une association avec des enfants dans factory_girl

Je voudrais une usine qui crée un Foo qui contient une barre. Idéalement, cette barre devrait être créée par l'intermédiaire de: la fabrique de barres, et respecter la stratégie de construction (créer/construire) utilisée pour créer le Foo. Je sais que je pourrais juste appeler l'usine de barre et puis saisir la référence de Foo de la nouvelle barre. J'aimerais éviter cela dans mon cas de test, l'objet important est Foo; appeler l'usine du Bar semble un peu détourné. En outre, je peux voir le besoin d'un Foo avec plusieurs barres.

Est-ce possible dans factory_girl? Comment définissez-vous cette relation dans le parent?

Répondre

48

Le Factory.after_ hooks semble être la seule façon de le faire avec succès. Je l'ai trouvé un moyen de maintenir la stratégie de construction sans dupliquer le code:

Factory.define :foo do |f| 
    f.name "A Foo" 
    f.after(:build) { |foo| 
    foo.bars << Factory.build(:bar, :foo => foo) 
    } 
    f.after(:create) { |foo| 
    foo.bars.each { |bar| bar.save! } 
    } 
end 

Les Etats qui documentationafter_build sera appelée avant after_create si la stratégie de construction :create est utilisée. Si :build est utilisé, alors seulement after_build est appelée, et tout le monde est content.

J'ai également créé une version abstraite généralement applicable at this gist pour garder les choses au sec.

+2

parfait - m'ont arraché les cheveux par-dessus. Merci! – recurser

+2

Il est difficile de croire que c'est la meilleure façon de le faire, mais il semble toujours être le cas. Up-voté cette réponse. – spier

+0

Comment utilisez-vous votre version d'origine? Quelle est la meilleure façon d'intégrer cela dans une application Rails? –

4

Vous pouvez utiliser la méthode association deux façons:

Factory.define :foo do |f| 
    # ... 
    f.association :bar 
end 

Si cela ne fonctionne pas, vous pouvez les associer manuellement à l'aide d'un rappel. Voici un exemple d'une de mes applications:

Factory.define :live_raid do |raid| 
end 

Factory.define :live_raid_with_attendee, :parent => :live_raid do |raid| 
    raid.after_create { |r| Factory(:live_attendee, :live_raid => r) } 
end 
+1

La première syntaxe provoque un débordement de pile/récursion infinie dans mon code. La deuxième syntaxe fonctionne à merveille, sauf qu'elle n'obéit pas à la stratégie de construction. –

3

factorygirl 4.3.0 appelle save! sur une association lors de l'appel build sur l'objet parent, qui je crois est pas destinée à être le bon comportement.

Après avoir creusé le code FactoryGirl, ajouter strategy: :build à la définition d'association en usine semble maintenant créer mon association sans appeler save!.

2

En utilisant factory_girl-4.5.0, créer des objets enfants n dans une usine d'objet parent

FactoryGirl.define do 
    factory :foo do 
    name "test"   

    after(:build) do |instance| 
     n.times { instance.bars << FactoryGirl.create(:bar) }   
    end 
    end 
end 
Questions connexes