2012-06-01 52 views
10

我是FactoryGirl的新手,我正在嘗試以下簡單場景?工廠女孩與現有對象創建關聯

factory :female, :class => Gender do 
    code 'Female' 
end 

factory :male, :class => Gender do 
    code 'Male' 
end 

factory :papas, :class => Customer do 
    first_name 'Jim' 
    last_name 'Papas' 
    association :gender, :factory => :male, :strategy => :build 
end 

factory :dumas, :class => Customer do 
    first_name 'Mary' 
    last_name 'Dumas' 
    association :gender, :factory => :female, :strategy => :build 
end 

然後在我的測試:

create(:male) 
create(:female) 
create(:papas) 
create(:dumas) 

注意,Customer類具有ASSOCATION belongs_toGender類和說gender_id應該存在一個驗證規則。我還對Gender類進行了驗證,以驗證代碼的唯一性。

create(:papas)上述說法,在我的測試中,我得到的錯誤是將要創建的Customer是無效的,因爲gender_idnil

如果我刪除與性別:strategy => :buildCustomer:papas工廠協會的話,我會得到一個錯誤,即試圖創建:papas時,爲性別代碼已經存在。

我需要做什麼以便我的測試按照上面的要求創建數據?

請注意,在其他測試中,我還希望在沒有客戶的情況下創建性別。不要告訴我用工廠創建命令創建客戶,並讓客戶同時創建性別。如果我嘗試創建兩個同一性別的客戶,這也不起作用。

此外,必須有一個比一個更好的答案:

@male = create(:male) 
@female = create(:female) 
create(:papas, :gender => @male) 
create(:dumas, :gender => @female) 

(?當使用固定裝置,這些事情都準備出的現成要我返回到夾具)

回答

14

您可以通過在您的客戶工廠中不使用工廠來實現您的性別實例並使用回調來實現您想要的目標。

你並沒有從性別工廠那裏獲得很多好處(儘管我很欣賞可以簡化它來提出這個問題)。你可以很容易地做到這一點得到了一個性別:

Gender.find_or_create_by_code!('Male') 

然後在客戶的工廠,你可以回調之前使用一個設置性別:

factory :dumas, :class => Customer do 
    first_name 'Mary' 
    last_name 'Dumas' 
    before_create do |customer| 
    customer.gender = Gender.find_or_create_by_code!('Female') 
    end 
end 

格式使用回調在factory_girl有最近或改變的,所以如果你使用3.3以後,你需要做的:

before(:create) do |customer| 

,而不是before_create

如果創建性別比您的示例更復雜,您仍然可以使用工廠創建性別,但使用find_by_code!find_or_create_by_code!之間的回調將其與客戶掛鉤。

+0

雖然相當冗長VS燈具,你的答案是正確的。過去兩個月我一直在使用工廠女孩,而我的下一個項目仍將使用燈具! –

+1

您可能會發現工廠的優勢在於您是否需要創建許多不同的客戶。您可以有一個male_customer和female_customer工廠,並將這些工廠用作不同客戶的父級工廠 - 這大大減少了冗長。很高興它的工作雖然! – Shadwell

5

ignore塊可用於包裝這件事還有:

factory :dumas, :class => Customer do 
    ignore do 
    female { Gender.find_by_code('Female') || create(:female) } 
    end 

    first_name 'Mary' 
    last_name 'Dumas' 
    gender { female } 
end 
5

ignore已被棄用,將在工廠女孩的5版本中刪除。

相反,你可以使用transient attributes

factory :dumas, :class => Customer do 
    transient do 
    female { Gender.find_by_code('Female') || create(:female) } 
    end 

    first_name 'Mary' 
    last_name 'Dumas' 
    gender { female } 
end