2013-01-21 13 views
28

Zmagam się z nawiązaniem relacji has_many/through za pomocą Factory Girl.Fabryka Dziewczyna: Jak skonfigurować asocjację has_many/through

mam następujące modele:

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 

moja fabryka:

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 

Co chcę jest moja fabryka praca ma zostać utworzony z domyślną Detail z "Full Time".

Próbowałem się do tego, ale nie miał szczęścia: FactoryGirl Has Many through

nie jestem pewien, w jaki sposób after_create należy stosować do mocowania detalu poprzez JobDetail.

Odpowiedz

30

Spróbuj czegoś takiego. Chcesz zbudować obiekt detail i dołączyć go do powiązania szczegółów zadania. Podczas korzystania z after_create utworzone zadanie zostanie przekazane do bloku. Możesz więc użyć FactoryGirl do utworzenia obiektu szczegółowego i dodać go bezpośrednio do szczegółów tego zadania.

factory :job do 
    ... 

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

To zadziałało, wielkie dzięki. Jedno pytanie - dodanie utworów after_create, ale odpowiada "DEPRECATION WARNING": Próbujesz utworzyć atrybut 'detail_id '. Zapisywanie dowolnych atrybutów w modelu jest przestarzałe. Proszę po prostu użyć 'attr_writer' etc.' jakichkolwiek pomysłów? – cman77

+11

Wiem, że jest stary, ale w FactoryGirl używasz teraz wywołań zwrotnych w formacie 'after (: create)' zamiast 'after_create' Reszta odpowiedzi powinna nadal działać bez błędów. – Arel

+0

więcej informacji o wywoływaniach 'after (: create)': http://robots.thoughtbot.com/get-your-callbacks-on-with-factory-girl-3-3 – Brian

2

ten pracował dla mnie

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 

Później

# 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

Wiem, że to jest stare, ale jestem ciekawy, co sprawia, że ​​jest to lepsze niż akceptowana tutaj odpowiedź? – rorykoehler

+0

Kiedy przeczytałem oryginalną odpowiedź, nie było wystarczająco dużo informacji w moim przykładzie. To również dodaje dodatkową funkcjonalność do tej odpowiedzi, ponieważ możesz użyć 'create: job_with_detail' z opcją' detail: @ detail' lub bez niej, a jeśli nie zostanie ona podana, szczegóły zostaną utworzone automatycznie. – Nate

4

I wobec tego problemu dzisiaj i znalazłem rozwiązanie. Mam nadzieję, że to pomaga komuś.

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 

Pozwala to stworzyć taką pracę

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

działa świetnie z najnowszym wszystkim od teraz (szyny 5, rspec 3.5, fabryka 4.8) – jpwynn

0

można rozwiązać ten problem w następujący sposób:

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 

z tym, można stworzyć job_with_details, że ma opcje, aby określić, ile szczegółów chcesz. Aby uzyskać więcej informacji, przeczytaj artykuł this interesting article.