Factory Girl: Как связать запись с другой записью, не создавая новую запись? - PullRequest
18 голосов
/ 26 октября 2010

Я использую Factory Girl / Rspec2 / Rails 3.

В factory.rb , у меня есть:

Factory.define :user do |user|
  user.name       'Some guy'
  user.email      'some_guy@somewhere.org'
  user.password   'password'
end

Factory.define :org_admin, :parent => :user do |user|
  user.email 'org_admin@somehwere.org'
end

Factory.define :user_with_membership_request, :parent => :user do |user|
  user.email 'user_with_membership_request@somehwere.org'
end

Factory.define :organization do |org|
  org.name        'MEC'
  org.description 'Mountain Equipment Co-op'
end

Factory.define :membership do |membership|
  membership.user { Factory(:user) }
  membership.organization { Factory(:organization) }
end

Factory.define :admin_membership, :parent => :membership do |membership|
  membership.user { Factory(:org_admin) }
  membership.is_admin true
  membership.status 'active'
end

Factory.define :membership_request, :parent => :membership do |membership|
  membership.user { Factory(:user_with_membership_request) }
  membership.status 'requested'
end

и затем в моем тесте rspec у меня есть:

  it 'should accept the membership request' do
    @org_admin = Factory(:org_admin)
    test_sign_in(@org_admin)
    @organization = Factory(:organization)
    @membership_request = Factory(:membership_request)

    put :update, :organization_id => @organization.id, :id => @membership_request.id, :acceptance => 'approve'
    ...
  end

Когда я запускаю тест, я получаю:

 Failure/Error: @membership_request = Factory(:membership_request)
 Validation failed: Name has already been taken

Я понимаю, что причина сбоя в том, что FactoryGirl создает другую организацию (с тем же именем).

Но я хотел бы создать несколько членов, связанных с одной организацией. Как мне это сделать?

Спасибо.

Sean

Ответы [ 3 ]

19 голосов
/ 26 октября 2010

Вы можете проверить существующую организацию и использовать ее или создать, если таковой нет:

Factory.define :membership do |membership|
  membership.user { Factory(:user) }
  membership.organization { Organization.first || Factory(:organization) }
end

Обновление FactoryGirl 4+:

Factory.define do
  factory :membership do
    user { create(:user) }
    organization { Organization.first || create(:organization) }
  end
end

Другой подход заключается в использовании уникальных идентификаторов (например, имен) для каждой фабрики, которую вы хотите использовать повторно, затем используйте initialize_with для ее генерации:

factory :organization_1 do
  ignore { organization_name 'Sample Organization 1' }
  name { organization_name }
  initialize_with { Organization.find_or_create_by_name(organization_name) }
end

Теперь любая ссылка на :organization_1 всегда будет получать один и тот же Organization. Очевидно, что для этого вы должны использовать разные имена.

4 голосов
/ 26 октября 2010

Есть две вещи.1. Возможно, вы все еще захотите создать уникальные имена для Factory(:organisation), вы можете добиться этого, используя Factory.sequence, который сгенерирует его уникально для вас.2. Вы можете передать Factory(:membership_request, :organization => @organization), чтобы использовать существующий объект вместо создания нового.

2 голосов
/ 11 октября 2011

С mongoid вы можете объединить использование метода #find_or_create_by с Factory.attributes_for и сделать что-то подобное

factory :membership do
    organization { Organization.find_or_create_by(Factory.attributes_for(:organization))}
end

Я уверен, что ActiveRecord имеет нечто подобное.

...