2010-10-26 14 views
18

estoy usando fábrica de la muchacha/Rspec2/Rails 3.Factory Girl: ¿Cómo asociar un registro a otro registro sin crear un nuevo registro?

En factories.rb, que tengo:

Factory.define :user do |user| 
    user.name  'Some guy' 
    user.email  '[email protected]' 
    user.password 'password' 
end 

Factory.define :org_admin, :parent => :user do |user| 
    user.email '[email protected]' 
end 

Factory.define :user_with_membership_request, :parent => :user do |user| 
    user.email '[email protected]' 
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 

y luego en mi prueba rspec tengo:

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 

Cuando ejecuto la prueba, obtengo:

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

Entiendo que el motivo del error es porque FactoryGirl está creando otra organización (con el mismo nombre).

Pero lo que me gustaría hacer es crear varias membresías asociadas a la misma organización. ¿Cómo puedo hacer eso?

Gracias.

Sean

Respuesta

18

Se puede comprobar si hay una organización existente y utilizarla, o crear uno si no existe ninguno:

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

factorygirl 4+ actualización:

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

Otro enfoque es el uso de identificadores únicos (por ejemplo, : nombres) para cada fábrica que desee volver a utilizar, luego use initialize_with para generarlo:

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

Ahora cualquier referencia a :organization_1 siempre recuperará el mismo Organization. Obviamente, debe usar nombres distintos para que esto funcione.

+0

Gracias Zeteic. Yo he usado esto Funciona por ahora. (Aunque cuando hay más de una Org, creo que tendré que encontrar otra solución ... otro problema para otro día ". –

4

Hay dos cosas. 1. Quizás desee crear nombres únicos para Factory(:organisation), puede lograr eso usando Factory.sequence que lo generará exclusivamente para usted. 2. Puede pasar un Factory(:membership_request, :organization => @organization) para usar el objeto existente en lugar de crear uno nuevo.

+0

Gracias Kunday. También he usado esto ... parece que tengo que definir algo más que básico en la prueba rspec en lugar de en las fábricas.rb. Todavía necesito entender las fábricas y cómo usarlas en un nivel superior. Solo puedo marcar a uno de ustedes como correcto, aunque he utilizado ambas sugerencias. –

+0

Cool Sean. Por lo que noté del uso de factory_girl en los últimos meses, más del 50% de las pruebas dependen de algunos datos explícitos configurados a partir de la prueba rspec. Pero dada la cantidad de configuración de datos que no se hace cuando su modelo se vuelve complejo, sigue siendo así, supongo. Es bueno escuchar que lo hiciste funcionar. – Kunday

2

Con MongoId se puede tomar combinar el uso del método #find_or_create_by con Factory.attributes_for y hacer algo como esto

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

estoy seguro de ActiveRecord tiene algo similar.

Cuestiones relacionadas