2011-08-05 22 views
69

Ai đó có thể cho tôi biết liệu tôi có đang thiết lập sai cách không?Cách thiết lập nhà máy tại FactoryGirl với liên kết has_many

tôi có các mô hình sau đó có các hiệp hội has_many.through:

class Listing < ActiveRecord::Base 
    attr_accessible ... 

    has_many :listing_features 
    has_many :features, :through => :listing_features 

    validates_presence_of ... 
    ... 
end 


class Feature < ActiveRecord::Base 
    attr_accessible ... 

    validates_presence_of ... 
    validates_uniqueness_of ... 

    has_many :listing_features 
    has_many :listings, :through => :listing_features 
end 


class ListingFeature < ActiveRecord::Base 
    attr_accessible :feature_id, :listing_id 

    belongs_to :feature 
    belongs_to :listing 
end 

Tôi đang sử dụng Rails 3.1.rc4, FactoryGirl 2.0.2, 1.1.0 factory_girl_rails, và rspec. Dưới đây là rspec rspec kiểm tra của tôi cơ bản sự tỉnh táo cho nhà máy :listing:

it "creates a valid listing from factory" do 
    Factory(:listing).should be_valid 
end 

Đây là Nhà máy (: niêm yết)

FactoryGirl.define do 
    factory :listing do 
    headline 'headline' 
    home_desc 'this is the home description' 
    association :user, :factory => :user 
    association :layout, :factory => :layout 
    association :features, :factory => :feature 
    end 
end 

Các :listing_feature:feature nhà máy là tương tự như thiết lập.
Nếu dòng association :features được nhận xét, thì tất cả các thử nghiệm của tôi đều được chuyển.
Khi nó là

association :features, :factory => :feature 

được thông báo lỗi là undefined method 'each' for #<Feature> mà tôi nghĩ có ý nghĩa với tôi bởi vì vì listing.features lợi nhuận một mảng. Vì vậy, tôi đã thay đổi nó để

association :features, [:factory => :feature] 

và lỗi tôi có được bây giờ là ArgumentError: Not registered: features Là nó chỉ không hợp lý để được tạo nhà máy đối tượng theo cách này, hoặc những gì tôi bị mất? Cảm ơn rất nhiều cho bất kỳ và tất cả các đầu vào!

Trả lời

50

Tạo các loại liên kết này yêu cầu sử dụng gọi lại của FactoryGirl.

Có thể tìm thấy một bộ ví dụ hoàn hảo tại đây.

http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl

Để mang nó về nhà làm ví dụ của bạn.

Factory.define :listing_with_features, :parent => :listing do |listing| 
    listing.after_create { |l| Factory(:feature, :listing => l) } 
    #or some for loop to generate X features 
end 
+0

bạn có sử dụng liên kết: tính năng, [: factory =>: feature] không? – davidtingsu

81

Hoặc, bạn có thể sử dụng khối và bỏ qua từ khóa association. Điều này làm cho nó có thể xây dựng các đối tượng mà không lưu vào cơ sở dữ liệu (nếu không, một liên kết has_many sẽ lưu các bản ghi của bạn vào db, ngay cả khi bạn sử dụng hàm build thay vì create).

FactoryGirl.define do 
    factory :listing_with_features, :parent => :listing do |listing| 
    features { build_list :feature, 3 } 
    end 
end 
+4

Đây là meow của mèo. Khả năng cho cả 'build' và' create' làm cho nó trở thành mẫu linh hoạt nhất. Sau đó, sử dụng chiến lược xây dựng FG tùy chỉnh này https://gist.github.com/Bartuz/74ee5834a36803d712b7 để 'đăng nested_attributes_for' khi kiểm tra các hành động của trình điều khiển mà' accept_nested_attributes_for' –

+3

upvoted, dễ đọc hơn và linh hoạt hơn câu trả lời được chấp nhận IMO –

18

Tôi đã thử một vài phương pháp khác nhau và đây là một trong những hoạt động đáng tin cậy nhất đối với tôi (phù hợp với trường hợp của bạn)

FactoryGirl.define do 
    factory :user do 
    # some details 
    end 

    factory :layout do 
    # some details 
    end 

    factory :feature do 
    # some details 
    end 

    factory :listing do 
    headline 'headline' 
    home_desc 'this is the home description' 
    association :user, factory: :user 
    association :layout, factory: :layout 
    after(:create) do |liztng| 
     FactoryGirl.create_list(:feature, 1, listing: liztng) 
    end 
    end 
end 
0

Dưới đây là cách tôi đặt mìn lên:

# Model 1 PreferenceSet 
class PreferenceSet < ActiveRecord::Base 
    belongs_to :user 
    has_many :preferences, dependent: :destroy 
end 

#Model 2 Preference 

class Preference < ActiveRecord::Base  
    belongs_to :preference_set 
end 



# factories/preference_set.rb 

FactoryGirl.define do 
    factory :preference_set do 
    user factory: :user 
    filter_name "market, filter_structure" 

    factory :preference_set_with_preferences do 
     after(:create) do |preference| 
     create(:preference, preference_set: preference) 
     create(:filter_structure_preference, preference_set: preference) 
     end 
    end 
    end 

end 

# factories/preference.rb 

FactoryGirl.define do 
    factory :preference do |p| 
    filter_name "market" 
    filter_value "12" 
    end 

    factory :filter_structure_preference, parent: :preference do 
    filter_name "structure" 
    filter_value "7" 
    end 
end 

Và sau đó trong các thử nghiệm của bạn, bạn có thể làm:

@preference_set = FactoryGirl.create(:preference_set_with_preferences) 

Hy vọng điều đó sẽ hữu ích.

11

Bạn có thể sử dụng trait:

FactoryGirl.define do 
    factory :listing do 
    ... 

    trait :with_features do 
     features { build_list :feature, 3 } 
    end 
    end 
end 

Với callback, nếu bạn cần DB tạo:

... 

trait :with_features do 
    after(:create) do |listing| 
    create_list(:feature, 3, listing: listing) 
    end 
end 

sử dụng trong thông số kỹ thuật của bạn như thế này:

let(:listing) { create(:listing, :with_features) } 

này sẽ loại bỏ sự trùng lặp trong các nhà máy của bạn và có thể tái sử dụng nhiều hơn.

https://robots.thoughtbot.com/remove-duplication-with-factorygirls-traits

Các vấn đề liên quan