2011-10-04 11 views
23

Mam dwa modele (ModelA i ModelB) i fabryki FactoryGirl dla każdego. Chcę, aby fabryka dla ModelB mogła (A) tworzyć dane testowe i (B) budować (bez zapisywania do bazy danych) przykładowe dane do wyświetlania klientom. Mam problem z uzyskaniem (A) do pracy z powodu sprawdzania poprawności Rails w moich modelach.Walidacje obejść podczas tworzenia obiektów FactoryGirl

MODELA:

class ModelA < ActiveRecord::Base 
    belongs_to :model_b 
    validates_presence_of :model_b 
end 

Fabryka do MODELA:

FactoryGirl.define do 
    factory :model_a do 
    some_attr "hello" 
    model_b { FactoryGirl.build :model_b } 
    end 
end 

ModelB

class ModelB < ActiveRecord::Base 
    has_one :model_a 
end 

Fabryka do ModelB

FactoryGirl.define do 
    factory :model_b do 
    some_attr "goodbye" 
    end 
end 

nie mogę tworzyć przedmioty z tych fabryk bez uzyskania błędy sprawdzania poprawności:

ruby> FactoryGirl.create :model_a 
ActiveRecord::RecordInvalid: Validation failed: ModelB can't be blank 

Wydaje się, że FactoryGirl próbuje zapisać obiekt fabryczny przed zapisaniem swoich assocations. Zdaję sobie sprawę, że mógłbym mieć fabrykę dla ModelB, aby utworzyć skojarzony ModelA (zamiast ją budować) - jednak straciłbym elastyczność, mogąc wykorzystać fabrykę ModelA do budowania przykładowych danych lub zapisywania danych testowych. Ewentualnie mogę usunąć zatwierdzenia; ale wtedy nie miałbym walidacji.

Jakieś inne opcje?

Odpowiedz

17

Spojrzałem na kilka rozwiązań.

Jednym z nich jest stworzenie własnego serwera proxy, ilustrowaną tutaj: http://codetunes.com/2009/11/05/fixtures-without-validation-with-factory-girl

Drugi to ustawić to_create bloku w fabryce:

FactoryGirl.define do 
    factory :model_a do 
    model_b { FactoryGirl.build :model_b }  

    to_create do |instance| 
     instance.model_b.save! 
     instance.save! 
    end 
    end 
end 
+0

Świetna poprawka. Bardzo mi pomogło. –

+0

Niestandardowy serwer proxy nie działa z FYI. default_strategy została usunięta tutaj: https://github.com/thoughtbot/factory_girl/commit/76235313240c17db663fe7f2868d7f0ecdea72d8#diff-2856f806bf47808e13bc8dc0baf374db – Geesu

+0

Lub zobacz: https://github.com/thoughtbot/factory_girl/issues/578 –

2

Ta okrężna weryfikacja nie jest dobrym pomysłem. W jaki sposób zamierzasz budować prawdziwe obiekty w bazie danych? Imho, to jest po prostu niemożliwe.

Najpierw należy zapisać obiekty do bazy danych, identyfikator jest przypisywany przez bazę danych i dopiero po zbudowaniu/zapisaniu obiektu można odwołać się do obiektu za pomocą identyfikatora w kluczu obcym. Aby móc odnosić się do rekordu w bazie danych, należy go najpierw zapisać. Ale jeśli sprawdzanie poprawności wymaga, aby identyfikatory były znane i obecne przed zapisaniem ...

W relacji belongs_to klucz obcy znajduje się w tabeli, a następnie można wyrazić potrzebę obecności klucza. W relacji has_one klucz obcy znajduje się w drugiej tabeli i nie można wyrazić walidacji, że element powinien być obecny. Powinieneś więc usunąć walidację z ModelB.

Mam nadzieję, że to pomoże.

[UPDATE]

Czy spróbować piśmie:

FactoryGirl.define do 
    factory :model_a do 
    some_attr "hello" 
    model_b 
    end 
end 
+0

Cześć - dziękuję za odpowiedź. Masz rację, nie powinienem był dokonywać walidacji cyklicznej. Zaktualizowałem mój pierwotny wpis. Po wprowadzeniu poprawek nadal pozostaje mój pierwotny problem: nie mogę tworzyć fabrycznych wystąpień ModelA za pomocą 'FactoryGirl.create: model_a'. – maxenglander

+0

Postępowałem zgodnie z twoją ostatnią radą i zastąpiłem mój leniwy atrybut 'association: model_b,: method =>: build' - właśnie tego potrzebowałem! Dziękuję Ci. – maxenglander

24

Jak na ten temat?

FactoryGirl.build(:model_a).save(validate: false) 

EDIT: Jak Scott McMillin komentarze poniżej, jeśli chcesz zbudowany obiekt jako zmienną, można to zrobić:

model_a = FactoryGirl.build(:model_a) 
model_a.save(validate: false) 
+0

Nie wiem o OP, ale to mi pomogło! Dzięki! –

+1

Uwaga: Ten jednokanałowy zwraca instancję TrueClass, a nie ModelA. Jeśli chcesz użyć instancji, wykonaj: 'model_a = kompilacja (: model_a); model_a.save (sprawdzanie poprawności: fałsz) ' –