2010-05-30 6 views
40

Ho un modello che has_many 'Bar'. Ho una fabbrica factory_girl per ciascuno di questi oggetti. La fabbrica di Bar ha un'associazione con Foo; istanzia un Foo quando crea la Barra.Compilazione di un'associazione con figli in factory_girl

Mi piacerebbe una Fabbrica che crea un Foo che contiene una Barra. Idealmente questa barra verrebbe creata attraverso: bar factory e rispetterà la strategia di build (create/build) utilizzata per creare Foo.

So che potrei semplicemente chiamare la fabbrica: bar e poi prendere il riferimento Foo dalla nuova barra. Mi piacerebbe evitare questo; nel mio caso di test, l'oggetto importante è Foo; chiamare la fabbrica del bar sembra un po 'tortuoso. Inoltre, posso vedere la necessità di un Foo con più barre.

E 'possibile in factory_girl? Come definisci questa relazione nel genitore?

risposta

48

La Factory.after_ hooks sembra essere l'unico modo per farlo con successo. Ho trovato un modo per mantenere la strategia di costruire senza duplicare il codice:

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 

Le documentation stati che after_build è chiamato prima after_create se si utilizza la strategia :create build. Se viene utilizzato :build, viene chiamato solo after_build e tutti sono felici.

Ho anche creato una versione astratta applicabile in generale at this gist per mantenere le cose ASCIUTTE.

+2

perfetto - mi sono strappato i capelli. Grazie! – recurser

+2

È difficile credere che questo sia il modo migliore per farlo, ma sembra essere il caso. Up-votato questa risposta. – spier

+0

Come usi la tua versione di Gist? Qual è il modo migliore per incorporarlo in un'app Rails? –

4

È possibile utilizzare il metodo association in entrambi i modi:

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

Se questo non funziona, è possibile associare manualmente utilizzando un callback. Ecco un esempio da una delle mie applicazioni:

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 prima sintassi causa un un overflow dello stack/ricorsione infinita nel mio codice. La seconda sintassi funziona meravigliosamente, tranne che non obbedisce alla strategia di costruzione. –

3

factorygirl 4.3.0 chiede save! su un'associazione quando si chiama build sull'oggetto genitore, che credo non è destinato ad essere il comportamento corretto.

Dopo aver scavato il codice FactoryGirl, aggiungere strategy: :build alla definizione dell'associazione in fabbrica sembra ora creare la mia associazione senza chiamare save!.

2

Utilizzando factory_girl-4.5.0, creare n oggetti figlio in una fabbrica oggetto padre

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

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