Has_many 연관을 사용하여 FactoryGirl에서 공장을 설정하는 방법


89

내가 잘못된 방식으로 설정하는 경우 누군가 말해 줄 수 있습니까?

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

저는 Rails 3.1.rc4, FactoryGirl 2.0.2, factory_girl_rails 1.1.0 및 rspec을 사용하고 있습니다. 다음은 :listing공장에 대한 기본적인 rspec rspec 온 전성 검사입니다 .

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

여기는 Factory (: listing)

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

:listing_feature:feature공장 유사하게 설정합니다.
는 IF association :features라인이 주석 다음 내 모든 테스트를 통과.

association :features, :factory => :feature

오류 메시지는 배열을 반환 undefined method 'each' for #<Feature> 하기 때문에 나에게 의미가 있다고 생각했습니다 listing.features. 그래서 나는 그것을

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

그리고 지금 내가 얻는 오류는 ArgumentError: Not registered: features 이런 식으로 팩토리 객체를 생성하는 것이 합리적이지 않습니까? 아니면 무엇을 놓치고 있습니까? 모든 의견에 감사드립니다!

답변:


57

이러한 종류의 연결을 생성하려면 FactoryGirl의 콜백을 사용해야합니다.

완벽한 예는 여기에서 찾을 수 있습니다.

https://thoughtbot.com/blog/aint-no-calla-back-girl

당신의 모범으로 그것을 집으로 가져 오십시오.

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

연관 : features, [: factory => : feature]를 사용하게 되었습니까?
davidtingsu 2013

108

또는 블록을 사용하고 association키워드를 건너 뛸 수 있습니다 . 이렇게하면 데이터베이스에 저장하지 않고 객체를 빌드 할 수 있습니다 (그렇지 않으면 has_many 연결은 build대신 함수 를 사용하더라도 레코드를 db에 저장합니다 create).

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

5
이것은 고양이의 야옹입니다. 양쪽에 능력 buildcreate그것을 가장 다양한 패턴이 있습니다. 그런 다음이 사용자 정의 FG 빌드 전략 사용 gist.github.com/Bartuz/74ee5834a36803d712b7post nested_attributes_for컨트롤러 액션을 테스트 할 때를 그accepts_nested_attributes_for
크리스 벡

4
훨씬 더 읽기 쉽고 다양한 IMO 허용 대답보다 upvoted,
m_x

1
FactoryBot 5부터 association키워드는 상위 및 하위에 대해 동일한 빌드 전략을 사용합니다. 따라서 데이터베이스에 저장하지 않고도 개체를 만들 수 있습니다.
Nick

27

다음을 사용할 수 있습니다 trait.

FactoryGirl.define do
  factory :listing do
    ...

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

를 사용하여 callbackDB 생성이 필요한 경우 :

...

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

다음과 같은 사양에서 사용하십시오.

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

이렇게하면 공장에서 중복이 제거되고 재사용이 더 쉬워집니다.

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


20

몇 가지 다른 접근 방식을 시도했는데 이것이 저에게 가장 안정적으로 작동 한 방식입니다 (귀하의 경우에 적용됨).

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

내 설정 방법은 다음과 같습니다.

# 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

그런 다음 테스트에서 다음을 수행 할 수 있습니다.

@preference_set = FactoryGirl.create(:preference_set_with_preferences)

도움이되기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.