113

Учитывая следующиеКак создать has_and_belongs_to_many ассоциации в Factory Girl

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 

Возможно удивительно это приводит к бесконечному циклу, как заводы рекурсивно используют друг друга, чтобы определить себя.

Более удивительно, что я не нашел упоминания о том, как это сделать в любом месте, есть ли образец для определения необходимых фабрик или я делаю что-то принципиально неправильно?

ответ

40

Factorygirl с тех пор обновлен и теперь включает обратные вызовы для решения этой проблемы. Взгляните на http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl для получения дополнительной информации.

+36

Ссылка на самом деле не говорит, как обрабатывать has_and_belongs_to_many ... Я не вижу, как это сделать ... – dmonopoly

+3

Синтаксис обратного вызова теперь изменен на: 'after (: create)' вместо 'after_create' на фабрике девочка, как упомянуто здесь: http://stackoverflow.com/questions/15003968/undefined-method-after-create-with-factorygirl –

0

Прежде всего, я настоятельно рекомендую вам использовать has_many: через вместо HABTM (подробнее об этом here), так что вы будете в конечном итоге с чем-то вроде:

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

Не должно быть «Занятость принадлежит_то: пользователю» и «Занятость принадлежит_от: компании» с моделью подключения, соединяющей одну компанию с одним пользователем? –

+5

Мое заключение из быстрого прочтения сообщения, которое вы упомянули, заключается в том, что это зависит от вашего варианта использования: выбирать ли habtm или has_many: through. Нет реального «победителя». – auralbee

+0

Ну, только накладные расходы при использовании hmt - это то, что вы должны иметь идентификатор, определенный на сквозной таблице. Прямо сейчас, я не могу представить ситуацию, когда это может вызвать проблемы. Я не говорю, что habtm бесполезен, просто в 99% случаев использования имеет смысл использовать hmt (из-за его преимуществ). –

5

Для меня работала установка ассоциации при использовании фабрики. Используя ваш пример:

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

company.users << user 
company.save! 
9

Я couldn't найти пример для вышеупомянутого случая на поставленном сайте. (Только 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

Что делать, если есть проверка количества ненулевых пользователей? – dfens

22

На мой взгляд, просто создать два различных заводов, как:

 
Factory.define :user, :class => User do |u| 
    # Just normal attributes initialization 
end 

Factory.define :company, :class => Company do |u| 
    # Just normal attributes initialization 
end 

Когда вы пишете тест-кейсы для пользователя, то просто написать как это

 
Factory(:user, :companies => [Factory(:company)]) 

Надеюсь, что это сработает.

+2

Спасибо, что это единственный пример, который я мог бы получить. Фабричная девушка - большая головная боль для habtm. – jspooner

+0

Это больше не работает с последними версиями FactoryGirl (я думаю, Rails 3) – Raf

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

+3

Не должно быть: 'after_create {| company, оценщик | FactoryGirl.create_list (: пользователь, оценщик.users_count, компании: [company]) } ' ? – Raf

120

Вот решение, которое работает для меня.

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

Спасибо, самый опрятный из всех решений. –

+0

Спасибо. Это устранило мою проблему после нескольких часов разочарования. –

+0

Это работает только для меня, когда все фабрики находятся в * одном файле *, что совершенно нежелательно. Поэтому решение, упомянутое ниже на @opsb, кажется лучше. – spier

1

Нашел способ красиво и многословным:

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

    factory :bar do 
    name "Bar" 
    foos { |a| [a.association(:foo)] } 
    end 
end 
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)

Подробное описание можно найти по адресу factory girl associations here.