2013-01-21 11 views
28

Ho avuto difficoltà a impostare una relazione has_many/through utilizzando Factory Girl.Factory Girl: come configurare un'associazione has_many/through

Ho i seguenti modelli:

class Job < ActiveRecord::Base 
    has_many :job_details, :dependent => :destroy 
    has_many :details, :through => :job_details 
end 

class Detail < ActiveRecord::Base 
    has_many :job_details, :dependent => :destroy 
    has_many :jobs, :through => :job_details 
end 

class JobDetail < ActiveRecord::Base 
    attr_accessible :job_id, :detail_id 
    belongs_to :job 
    belongs_to :detail 
end 

My Factory:

factory :job do 
    association  :tenant 
    title   { Faker::Company.catch_phrase } 
    company   { Faker::Company.name } 
    company_url  { Faker::Internet.domain_name } 
    purchaser_email { Faker::Internet.email } 
    description  { Faker::Lorem.paragraphs(3) } 
    how_to_apply { Faker::Lorem.sentence } 
    location  "New York, NY" 
end 

factory :detail do 
    association :detail_type <--another Factory not show here 
    description "Full Time" 
end 

factory :job_detail do 
    association :job 
    association :detail 
end 

Quello che voglio è per la mia fabbrica di posti di lavoro da creare con un valore predefinito Detail di "Full Time".

Ho cercato di seguire questo, ma non hanno avuto fortuna: FactoryGirl Has Many through

io non sono sicuro di come il after_create dovrebbero essere utilizzati per collegare il particolare via il JobDetail.

risposta

30

Prova qualcosa del genere. Si desidera creare un oggetto detail e aggiungerlo all'associazione dettagli del lavoro. Quando si utilizza after_create, il lavoro creato verrà restituito al blocco. Quindi puoi usare FactoryGirl per creare un oggetto di dettaglio e aggiungerlo direttamente ai dettagli di quel lavoro.

factory :job do 
    ... 

    after_create do |job| 
    job.details << FactoryGirl.create(:detail) 
    end 
end 
+0

Questo ha funzionato molto bene grazie. Una domanda: l'aggiunta di after_create funziona, ma risponde con 'AVVISO DEPRESSIONE: Stai cercando di creare un attributo' detail_id '. La scrittura di attributi arbitrari su un modello è deprecata. Per favore usa solo "attr_writer' ecc." Qualche idea? – cman77

+11

So che questo è vecchio, ma in FactoryGirl ora usi i callback con il formato 'after (: create)' invece di 'after_create' Il resto della risposta dovrebbe funzionare senza errori. – Arel

+0

maggiori informazioni su 'after (: create)' callbacks: http://robots.thoughtbot.com/get-your-callbacks-on-with-factory-girl-3-3 – Brian

2

questo ha lavorato per me

FactoryGirl.define do 
    factory :job do 

    # ... Do whatever with the job attributes here 

    factory :job_with_detail do 

     # In later (as of this writing, unreleased) versions of FactoryGirl 
     # you will need to use `transitive` instead of `ignore` here 
     ignore do 
     detail { create :detail } 
     end 

     after :create do |job, evaluator| 
     job.details << evaluator.detail 
     job.save 
     job_detail = job.job_details.where(detail:evaluator.detail).first 

     # ... do anything with the JobDetail here 

     job_detail.save 
     end 
    end 
    end 
end 

Poi più tardi

# A Detail object is created automatically and associated with the new Job. 
FactoryGirl.create :job_with_detail 

# To supply a detail object to be associated with the new Job. 
FactoryGirl.create :job_with_detail detail:@detail 
+0

So che questo è vecchio ma sono curioso di sapere cosa rende questo meglio della risposta accettata qui? – rorykoehler

+0

Quando ho letto la risposta originale, non c'erano abbastanza informazioni nell'esempio di mio gradimento. Questo aggiunge anche funzionalità aggiuntive in cima a quella risposta dato che puoi usare 'create: job_with_detail' con o senza l'opzione' detail: @ detail' e se non viene fornito, il dettaglio verrà creato automaticamente. – Nate

4

Ho affrontato questo problema oggi e ho trovato una soluzione. Spero che questo aiuti qualcuno.

FactoryGirl.define do 
    factory :job do 

    transient do 
     details_count 5 # if details count is not given while creating job, 5 is taken as default count 
    end 

    factory :job_with_details do 
     after(:create) do |job, evaluator| 
     (0...evaluator.details_count).each do |i| 
      job.details << FactoryGirl.create(:detail) 
     end 
     end 
    end 
    end 
end 

Questo permette di creare un lavoro come questo

create(:job_with_details) #job created with 5 detail objects 
create(:job_with_details, details_count: 3) # job created with 3 detail objects 
+0

funziona alla grande con tutto il più recente (rails 5, rspec 3.5, factorygirl 4.8) – jpwynn

0

È possibile risolvere questo problema nel modo seguente:

FactoryBot.define do 
    factory :job do 
    # job attributes 

    factory :job_with_details do 
     transient do 
     details_count 10 # default number 
     end 

     after(:create) do |job, evaluator| 
     create_list(:details, evaluator.details_count, job: job) 
     end 
    end 
    end 
end 

Con questo, è possibile creare una job_with_details, che ha opzioni per specificare quanti dettagli vuoi. Puoi leggere this interesting article per maggiori dettagli.

Problemi correlati