Заполнение ассоциации детьми в factory_girl

У меня есть модель Foo с множеством баров. У меня есть фабрика factory_girl для каждого из этих объектов. Фабрика для Бара ассоциируется с Фу; он создаст экземпляр Foo при создании Bar.

Я бы хотел, чтобы Factory создавала Foo, содержащую Bar. В идеале этот Bar должен быть создан с помощью фабрики :bar и учитывать стратегию сборки (создание/сборка), используемую для создания Foo.

Я знаю, что могу просто вызвать :bar factory, а затем взять ссылку Foo из нового Bar. Я хотел бы избежать этого; в моем тестовом примере важным объектом является Foo; звонить на барную фабрику кажется немного окольным путем. Кроме того, я вижу необходимость в Foo с несколькими барами.

Возможно ли это в factory_girl? Как вы определяете эту связь в родителях?


person Craig Walker    schedule 30.05.2010    source источник


Ответы (5)


Factory.after_ hooks кажется единственным способом сделать это успешно. Я нашел способ сохранить стратегию сборки без дублирования кода:

Factory.define :foo do |f|
  f.name "A Foo"
  f.after(:build) { |foo|
    foo.bars << Factory.build(:bar, :foo => foo)
  }
  f.after(:create) { |foo|
    foo.bars.each { |bar| bar.save! }
  }
end

В документации указано, что after_build будет вызываться перед after_create, если используется стратегия сборки :create. Если используется :build, то вызывается только after_build, и все довольны.

Я также создал абстрактную общеприменимую версию по существу, чтобы все было СУХИМ.

person Craig Walker    schedule 13.06.2010
comment
Трудно поверить, что это лучший способ сделать это, но, похоже, это все же так. Проголосовал за этот ответ. - person spier; 02.08.2013
comment
Как вы используете свою основную версию? Каков наилучший способ включить это в приложение Rails? - person joseph.hainline; 07.12.2013
comment
Как отмечено здесь, использование << для добавления ассоциации сохраняет изменения. Чтобы этого избежать, after(:build) должно быть foo.association(:bars).add_to_target(Factory.build(:bar, :foo => foo) ) - person stevenspiel; 09.02.2017

Вы можете использовать метод association в обоих направлениях:

Factory.define :foo do |f|
  # ...
  f.association :bar
end

Если это не сработает, вы можете связать их вручную с помощью обратного вызова. Вот пример из одного из моих приложений:

Factory.define :live_raid do |raid|
end

Factory.define :live_raid_with_attendee, :parent => :live_raid do |raid|
  raid.after_create { |r| Factory(:live_attendee, :live_raid => r) }
end
person Robert Speicher    schedule 30.05.2010
comment
Первый синтаксис вызывает переполнение стека/бесконечную рекурсию в моем коде. Второй синтаксис прекрасно работает, за исключением того, что он не подчиняется стратегии сборки. - person Craig Walker; 13.06.2010

FactoryGirl теперь имеет опцию :method => :build, которую вы можете использовать в ассоциации, которая будет создавать связанный объект, а не создавать его.

#64: Создание объекта создает ассоциации

person bjnord    schedule 12.11.2011

FactoryGirl 4.3.0 вызывает save! для ассоциации при вызове build для родительского объекта, что, я считаю, не должно быть правильным поведением.

После изучения кода FactoryGirl добавление strategy: :build к определению ассоциации на фабрике, похоже, теперь создает мою ассоциацию без вызова save!.

person mgp    schedule 29.12.2013

Используя factory_girl-4.5.0, создайте n дочерних объектов в фабрике родительских объектов.

FactoryGirl.define do
  factory :foo do
    name "test"        

    after(:build) do |instance|
      n.times { instance.bars << FactoryGirl.create(:bar) }          
    end
  end
end
person Epigene    schedule 15.04.2015