2012-12-13 20 views
17

Mam standardową relację has_many (Rezerwacja ma wiele zamówień) z potwierdzeniem, że Rezerwacja nie zostanie zapisana bez co najmniej jednego Zamówienia. Próbuję powtórzyć to z moimi fabrykami FactoryGirl, ale walidacja uniemożliwia mi to.FactoryGirl has_many association with validation

class Booking < ActiveRecord::Base 
    has_many :orders 
    validates :orders, presence: true 
end 

class Order < ActiveRecord::Base 
    belongs_to :booking 
end 

Oto moje specyfikacje fabryczne FactoyGirl dla każdego modelu, zgodnie ze stroną FactoryGirl na wiki GitHub.

FactoryGirl.define do              

    factory :booking do                             
    factory :booking_with_orders do 

     ignore do                               
     orders_count 1                             
     end                                

     before(:create) do |booking, evaluator|                       
     FactoryGirl.create_list(:order, evaluator.orders_count, booking: booking)              
     end                                
    end                                 
    end 

    factory :order do 
    booking 
    end 

end 

Kiedy próbuję uruchomić FactoryGirl.create(:booking_with_orders) z mojego specyfikacji, otrzymuję:

Failure/Error: @booking = FactoryGirl.create(:booking_with_orders) 
ActiveRecord::RecordInvalid: 
    Validation failed: Orders can't be blank 

Wydaje się, że czek na walidacji jest uruchomiony jeszcze przed before(:create) [...] które teoretycznie stworzyłoby Zamówienia za rezerwację.

This post zaleca, aby nie dodawać has_many relacji do swoich fabryk, ale chciałbym rozwiązać to tak czy inaczej, jeśli istnieje dobry sposób, aby to zrobić.

Z góry dziękuję.

Odpowiedz

30

Wat? Niemożliwy? Ani trochę.

Wystarczy zmienić swój kod na coś takiego:

after :build do |booking, evaluator| 
    booking.orders << FactoryGirl.build_list(:order, evaluator.orders_count, booking: nil) 
end 
+0

Masz na myśli 'booking.orders <<', ale poza tym była to odpowiedź dla mnie. Dzięki! – Jalada

+0

Ups! Naprawiono to, dziękuję za wskazanie go – jassa

+0

doskonałe! Wielkie dzięki! – gayavat

0

To wydaje się nazbyt uproszczony obserwacji, ale to, co próbujesz zrobić, to w efekcie upewnić, że Order istnieje przed Booking, co jest niemożliwe, gdyż Order nie może istnieć bez swojej booking_id (co oznacza, że ​​Booking potrzeb być najpierw stworzonym).

Nie ma nic złego w wielu związkach w twoich fabrykach, to twoja walidacja stanowi problem. Czy to obecnie działa w twojej aplikacji? Jak zachowujesz swoje rekordy w takim przypadku? Jaki jest przepływ do tworzenia zamówień i rezerwacji?

Nawet niesławny accepts_nested_attributes_for nie pomoże tutaj.

Moja rada to przemyślenie strategii zapisywania i walidacji zapisów, aby była trochę bardziej rozsądna.

+0

Dzięki, to jest dobra uwaga, ale wszystko działa w mojej aplikacji z walidacją. Oto mój przepływ: '@booking = Booking.new (params [: booking])' '{booking.orders << Order.new (params [: order])' '@ booking.save'. –

+0

@ErikNomitch Czy próbowałeś wywołania zwrotnego 'after (: build)' zamiast 'before (: create)'? Jak dokładnie konfigurowana jest funkcja sprawdzania poprawności w opcji "Rezerwacja"? Domyślam się, że FactoryGirl prawdopodobnie chce tworzyć te obiekty w izolacji, co ma sens z punktu widzenia testowania, ale kiedy je tworzysz, jak właśnie zauważyłeś w swoim komentarzu, są one tworzone razem. Ten rodzaj sprzężenia zwykle prowadzi do bólów głowy. – regulatethis

2

Startu od użytkownika @ Jassa odpowiedź, jeśli wystarczy dodać jeden (wymagane) powiązany rekord z konkretnego atrybutu, to wzór pracował dla mnie :

factory :booking do 
    ignore do 
    order_name "name" 
    end 

    after :build do |factory, evaluator| 
    factory.orders << FactoryGirl.build(:order, name: evaluator.order_name, booking: nil) 
    end 
end 
Powiązane problemy