Factory Girl에서 has_and_belongs_to_many 연결을 만드는 방법


119

다음을 감안할 때

class User < ActiveRecord::Base
  has_and_belongs_to_many :companies
end

class Company < ActiveRecord::Base
  has_and_belongs_to_many :users
end

양방향 연관을 포함하여 기업과 사용자를위한 공장을 어떻게 정의합니까? 여기 내 시도

Factory.define :company do |f|
  f.users{ |users| [users.association :company]}
end

Factory.define :user do |f|
  f.companies{ |companies| [companies.association :user]}
end

이제 나는 시도

Factory :user

당연히 공장이 서로를 재귀 적으로 사용하여 자신을 정의하기 때문에 무한 루프가 발생합니다.

더 놀랍게도 나는 이것을 어디에서나 수행하는 방법에 대한 언급을 찾지 못했습니다. 필요한 공장을 정의하는 패턴이 있습니까? 아니면 근본적으로 잘못하고 있습니까?

답변:


132

여기 저에게 맞는 솔루션이 있습니다.

FactoryGirl.define do

  factory :company do
    #company attributes
  end

  factory :user do
   companies {[FactoryGirl.create(:company)]}
   #user attributes
  end

end

특정 회사가 필요하면 이런 식으로 공장을 사용할 수 있습니다.

company = FactoryGirl.create(:company, #{company attributes})
user = FactoryGirl.create(:user, :companies => [company])

이것이 누군가에게 도움이되기를 바랍니다.


4
감사합니다. 가장 깔끔한 솔루션입니다.
Mik

감사합니다. 이것은 몇 시간의 좌절 후에 내 문제를 해결했습니다.
Tony Beninate 2012 년

이것은 모든 공장 이 매우 바람직하지 않은 하나의 파일 에있을 때만 작동합니다 . 따라서 아래 @opsb에서 언급 한 솔루션이 더 나은 것 같습니다.
스피어

40

Factorygirl은 이후 업데이트되었으며 이제이 문제를 해결하기위한 콜백을 포함합니다. 자세한 내용 은 http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl 을 참조하십시오.


37
링크는 실제로 ... 나는이 작업을 수행하는 방법을 볼 수 없습니다 ... has_and_belongs_to_many를 처리하는 방법을 말하지 않는다
dmonopoly

3
: 콜백 구문은 이제 변경되었습니다 after(:create)대신 after_create여기에 언급 한 바와 같이 공장 소녀에서 : stackoverflow.com/questions/15003968/...
마이클 Yagudaev

22

제 생각에는 다음과 같이 두 개의 다른 공장을 만드십시오.

 Factory.define : user, : class => User do | u |
  # 그냥 일반적인 속성 초기화
 종료

 Factory.define : company, : class => Company do | u |
  # 그냥 일반적인 속성 초기화
 종료

사용자에 대한 테스트 케이스를 작성할 때 다음과 같이 작성하십시오.

 Factory (: 사용자, : companies => [Factory (: company)])

그것이 효과가 있기를 바랍니다.


2
감사합니다 이것이 제가 일할 수있는 유일한 예입니다. 공장 소녀는 habtm에게 큰 골칫거리입니다.
jspooner

이것은 더 이상 FactoryGirl의 최신 버전에서 작동하지 않습니다 (나는 Rails 3을 생각하고 있습니다)
Raf

9

제공된 웹 사이트에서 위에 언급 된 사례에 대한 예를 찾을 수 없습니다. (1 : N 및 다형성 조합 만, habtm 없음). 비슷한 경우가 있었고 코드는 다음과 같습니다.

Factory.define :user do |user|
 user.name "Foo Bar"
 user.after_create { |u| Factory(:company, :users => [u]) }
end

Factory.define :company do |c|
 c.name "Acme"
end

3
0이 아닌 사용자 수에 대한 유효성 검사가 있으면 어떻게됩니까?
dfens 2011-06-07

5

나를 위해 일한 것은 공장을 사용할 때 협회를 설정하는 것이 었습니다. 귀하의 예를 사용하여 :

user = Factory(:user)
company = Factory(:company)

company.users << user 
company.save! 

4

이 방법이 멋지고 장황하다는 것을 알았습니다.

FactoryGirl.define do
  factory :foo do
    name "Foo" 
  end

  factory :bar do
    name "Bar"
    foos { |a| [a.association(:foo)] }
  end
end

1
foos { |a| [a.association(:foo)] }많이 도와주세요! 감사합니다!
monteirobrena

3
  factory :company_with_users, parent: :company do

    ignore do
      users_count 20
    end

    after_create do |company, evaluator|
      FactoryGirl.create_list(:user, evaluator.users_count, users: [user])
    end

  end

경고 : 루비 1.8.x의 경우 사용자 : [user]를 : users => [user]로 변경하십시오.


4
안돼 : after_create { |company, evaluator| FactoryGirl.create_list(:user, evaluator.users_count, companies: [company]) }?
Raf 2011

0

우선 habtm 대신 has_many : through를 사용하도록 강력히 권장합니다 ( 여기 에 대해 자세히 설명합니다 ). 그러면 다음과 같은 결과를 얻게됩니다.

Employment belongs_to :users
Employment belongs_to :companies

User has_many :employments
User has_many :companies, :through => :employments 

Company has_many :employments
Company has_many :users, :through => :employments

그 후에 양측에 has_many 연관성을 갖게되고 당신이했던 방식으로 factory_girl에서 그들에게 할당 할 수 있습니다.


3
되어서는 안된다는 Employment belongs_to :userEmployment belongs_to :company하나의 사용자와 하나의 회사를 연결하는 결합 모델?
Daniel Beardsley

5
언급 한 게시물을 빠르게 읽은 결과 내 결론은 habtm 또는 has_many : through를 선택할지 여부에 따라 사용 사례에 달려 있다는 것입니다. 진정한 "승자"는 없습니다.
auralbee 2011 년

음, hmt를 사용할 때 유일한 오버 헤드는 through 테이블에 id를 정의해야한다는 것입니다. 지금 당장은 그것이 문제를 일으킬 수있는 상황을 상상할 수 없습니다. 나는 habtm이 쓸모가 없다고 말하지 않고 단지 99 %의 사용 사례에서 hmt를 사용하는 것이 더 합리적이라고 말하지 않습니다 (그 장점 때문에).
Milan Novota 2011 년

6
-1, HMT가 더 많은 '장점'을 가지고 있기 때문에 그러한 이점이 필요한 경우에만 사용해야 함을 의미합니다. Pet peeve, 저는 개발자가 HABTM이 충분했을 여러 경우에 HMT를 사용하는 프로젝트를 진행하고 있기 때문입니다. 따라서 코드베이스는 더 크고 복잡하며 덜 직관적이며 이로 인해 더 느린 SQL 조인을 생성합니다. 따라서 가능하면 HABTM을 사용하고 각 연결에 대한 추가 정보를 저장하기 위해 별도의 조인 모델을 만들어야하는 경우에만 HMT를 사용합니다.
sbeam

0

Rails 5 업데이트 :

has_and_belongs_to_many연관 을 사용하는 대신 다음을 고려해야합니다. has_many :through연관.

이 연관의 사용자 팩토리는 다음과 같습니다.

FactoryBot.define do
  factory :user do
    # user attributes

    factory :user_with_companies do
      transient do
        companies_count 10 # default number
      end

      after(:create) do |user, evaluator|
         create_list(:companies, evaluator.companies_count, user: user)
      end
    end
  end
end

비슷한 방법으로 회사 공장을 만들 수 있습니다.

두 공장이 설정되면, 당신은 만들 수 user_with_companies와 공장 companies_count option. 여기에서 사용자가 속한 회사 수를 지정할 수 있습니다.create(:user_with_companies, companies_count: 15)

여기에서 공장 소녀 협회 에 대한 자세한 설명을 찾을 수 있습니다 .


0

HABTM의 경우 특성과 콜백을 사용했습니다 .

다음 모델이 있다고 가정합니다.

class Catalog < ApplicationRecord
  has_and_belongs_to_many :courses
  
end
class Course < ApplicationRecord
  
end

위의 Factory정의 할 수 있습니다 .

FactoryBot.define do
  factory :catalog do
    description "Catalog description"
    

    trait :with_courses do
      after :create do |catalog|
        courses = FactoryBot.create_list :course, 2

        catalog.courses << courses
        catalog.save
      end
    end
  end
end

-1

새 팩토리를 정의하고 after (: create) 콜백을 사용하여 연관 목록을 생성 할 수 있습니다. 이 예에서 방법을 살펴 보겠습니다.

FactoryBot.define do

  # user factory without associated companies
  factory :user do
    # user attributes

    factory :user_with_companies do
      transient do
        companies_count 10
      end

      after(:create) do |user, evaluator|
        create_list(:companies, evaluator.companies_count, user: user)
      end
    end
  end
end

Companies_count 속성은 일시적이며 팩토리 속성과 평가자를 통한 콜백에서 사용할 수 있습니다. 이제 원하는 회사 수를 지정하는 옵션이있는 회사 사용자를 만들 수 있습니다.

create(:user_with_companies).companies.length # 10
create(:user_with_companies, companies_count: 15).companies.length # 15
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.