2010-10-26 12 views
18

Sto usando Factory Girl/Rspec2/Rails 3.Factory Girl: come associare un record a un altro record senza creare un nuovo record?

In factories.rb, ho:

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 

e poi nel mio test rspec ho:

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 

Quando eseguo il test, ottengo:

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

Comprendo che il motivo dell'errore è dovuto al fatto che FactoryGirl sta creando un'altra organizzazione (con lo stesso nome).

Ma quello che mi piacerebbe fare è creare diversi abbonamenti tutti associati alla stessa organizzazione. Come lo faccio?

Grazie.

Sean

risposta

18

Si potrebbe verificare la presenza di un'organizzazione esistente e utilizzarlo, o crearne uno se non esiste:

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

factorygirl 4+ aggiornamento:

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

Un altro approccio è quello di utilizzare identificatori univoci (ad esempio, : nomi) per ogni fabbrica che si desidera riutilizzare, quindi utilizzare initialize_with per 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 

Ora qualsiasi riferimento a :organization_1 recupererà sempre lo stesso Organization. Ovviamente, è necessario utilizzare nomi distinti perché funzioni.

+0

Grazie Zeteic. L'ho usato. Funziona per ora. (anche se c'è più di una Org, credo che dovrò trovare un'altra soluzione .. un altro problema per un altro giorno ". –

4

Ci sono due cose. 1. È ancora possibile creare nomi univoci per Factory(:organisation) che è possibile ottenere utilizzando Factory.sequence che lo genererà in modo univoco per l'utente. 2. È possibile passare in un Factory(:membership_request, :organization => @organization) per utilizzare l'oggetto esistente anziché crearne uno nuovo.

+0

Grazie Kunday. Ho anche usato questo .. sembra che devo definire più di ogni cosa di base nel test rspec piuttosto che in factories.rb. Devo ancora capire le fabbriche e come usarle a un livello più alto. Posso solo contrassegnare uno di voi correttamente, anche se ho usato entrambi i vostri suggerimenti. –

+0

Cool Sean. Da quanto ho notato di usare factory_girl negli ultimi mesi, oltre il 50% dei test dipende da alcuni dati espliciti impostati dal test rspec. Ma data la quantità di configurazione dei dati che non fai quando il tuo modello diventa complesso va ancora bene, credo. Piacere di averti capito. – Kunday

2

Con mongoid si può prendere combinare l'uso del metodo #find_or_create_by con Factory.attributes_for e fare qualcosa di simile

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

sono sicuro ActiveRecord ha qualcosa di simile.

Problemi correlati