2012-10-24 60 views
6

我想弄清楚如何編寫屬於2個不同模型的工廠,每個模型都應該有相同的父模型。這裏是人爲的示例代碼:FactoryGirl與多個模型的複雜關聯

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 

這是我到目前爲止有:

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 

這樣做的問題是,part.widget.user != part.supplier.user,他們必須是相同的。

我嘗試沒有成功如下:

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

有什麼建議?或者在創建零件之後我必須修改它嗎?

謝謝

回答

7

我相信你可以用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 

參見:Get two associations within a Factory to share another association

+0

非常感謝。我結束了使用'後(:建設)'和'part.widget.user = part.supplier.user'這樣我不創建3個用戶:) –

+0

哦,太棒了,它的工作!我不太確定。在我看來,儘管如此,仍然必須有一種更清晰的方式。 –

+0

這就是我的想法,但'協會:供應商,用戶:widget.user'不起作用可能是一個補丁 –

0

另一種選擇是使用瞬態變量以允許相關的對象傳遞英寸

我一般使用兩個變量:

  • 持有該協會的變量要在工廠
  • 布爾變量中使用,用於指示是否產生了關聯變量的默認值 - 大概不會需要您的具體情況,但可以很有用

這是它會怎樣看:

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 

這然後可以在下列方式使用:

# 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