2012-10-24 13 views
6

Próbuję dowiedzieć się, jak napisać fabrykę należącą do 2 różnych modeli, z których każdy powinien mieć ten sam model nadrzędny. Oto wymyślony przykładowy kod:Kompleksowe powiązanie FactoryGirl z wieloma modelami

class User < ActiveRecord::Base 
    has_many :widgets 
    has_many :suppliers 

    attr_accessible :username 
end 

class Widget < ActiveRecord::Base 
    belongs_to :user 
    has_many :parts 

    attr_accessible :name 
end 

class Supplier < ActiveRecord::Base 
    belongs_to :user 
    has_many :parts 

    attr_accessible :name 
end 

class Part < ActiveRecord::Base 
    belongs_to :supplier 
    belongs_to :widget 

    attr_accessible :name 
end 

Oto co mam do tej pory:

factory :user do 
    name 'foo' 
end 

factory :widget do 
    association :user 
    name 'widget' 
end 

factory :supplier do 
    association :user 
    name 'supplier' 
end 

factory :part do 
    association :widget 
    association :supplier 
    name 'part' 
end 

Problem polega na tym, że part.widget.user != part.supplier.user i muszą być takie same.

Próbowałem następujących bez powodzenia:

factory :part do 
    association :widget 
    association :supplier, user: widget.user 
    name 'part' 
end 

jakieś sugestie? Czy muszę go modyfikować po utworzeniu części?

Dziękuję

Odpowiedz

7

wierzę, można zrobić to z callback:

factory :part do 
    association :widget 
    association :supplier 
    name 'part' 
    after(:create) do |part| 
    user = FactoryGirl.create(:user) 
    part.widget.user = part.supplier.user = user 
    end 
end 

Zobacz także: Get two associations within a Factory to share another association

+0

Wielkie dzięki. Skończyło się na użyciu 'after (: build)' i 'part.widget.user = part.supplier.user' w ten sposób nie tworzę 3 użytkowników :) –

+0

Świetnie, że zadziałało! Nie byłem do końca pewien. Wydaje mi się, że musi to być czystszy sposób. –

+0

Tak też myślałem, ale 'asocjacja: dostawca, użytkownik: widget.user' nie działa, może być czymś, na co warto zaglądać dla łaty –

0

Inną opcją jest użycie zmiennych przejściowych w celu umożliwienia skojarzony obiektu mają być przekazywane w.

Generalnie używam dwóch zmiennych:

  • Zmienna trzymać stowarzyszenie do wykorzystania w fabryce
  • Zmienna logiczna, aby wskazać, czy należy generować wartość domyślną dla zmiennej Stowarzyszenia - prawdopodobnie nie potrzebne w konkretnym przypadku, ale może być bardzo przydatna

to jak to będzie wyglądać:

factory :part do 
    transient do 
    # this variable is so we can specify the user 
    with_user { no_user ? nil : Factory.create(:user) } 

    # this variable allows the user to be nil 
    no_user false 
    end 

    # The transient variable for_user can now be used to create the 
    # associations for this factory 
    widget { Factory.create(:widget, :user => with_user) } 
    supplier { Factory.create(:supplier, :user => with_user) } 

    name 'part' 
end 

ten może być następnie wykorzystane w następujący sposób:

# use the default user 
part = Factory.create :part 
part.widget.user.should == part.supplier.user 

# use a custom created user 
user = Factory.create :user, :name => 'Custom user' 
part = Factory.create :part, for_user: user 
part.widget.user.should == user 
part.supplier.user.should == user 

# create a part without any user 
# (again this probably isn't need in your specific case, but I have 
# found it a useful pattern) 
part = Factory.create :part, no_user: true 
part.widget.user.should be_nil 
part.supplier.user.should be_nil 
Powiązane problemy