2012-12-13 151 views
17

我有一个标准的has_many关系(预订有很多订单),并验证预订在没有至少一个订单的情况下无法保存。我试图用我的FactoryGirl工厂复制这个,但验证正在阻止我这样做。FactoryGirl has_many与验证关联

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

class Order < ActiveRecord::Base 
    belongs_to :booking 
end 

这里是我的FactoyGirl出厂规格为每个模型从FactoryGirl的GitHub的wiki页面紧随其后。

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 

当我试图从我的规格运行FactoryGirl.create(:booking_with_orders),我得到:

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

这似乎是在检查甚至before(:create) [...]其理论上将创建预订的订单之前运行验证。

This post建议不要将has_many关系添加到您的工厂,但是我想解决这个问题,无论如何,如果有一个好的方法来做到这一点。

在此先感谢。

回答

30

Wat?不可能?一点也不。

只要改变你的代码是这样的:

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

您的意思是'booking.orders <<',否则,这是我的答案。谢谢! – Jalada

+0

哎呀!修好了,谢谢指出 – jassa

+0

优秀!非常感谢! – gayavat

0

这似乎是一个过于简单化的观察,但你想做什么实际上是确保该Order存在Booking,这是不可能的面前,因为Order离不开其booking_id存在(这意味着Booking需求首先创建)。

工厂中的has_many关系没有任何问题,这是您的验证问题。这目前是否在你的应用程序中工作?如何在这种情况下保存你的记录?创建订单和预订的流程是什么?

即使臭名昭着的accepts_nested_attributes_for也不会帮你在这里。

我的建议是重新考虑您的记录保存和验证策略,使其更加理智。

+0

谢谢,这是一个很好的考虑,但一切都在我的应用与验证工作。这里是我的流程:'@booking = Booking.new(params [:booking])'''booking.orders << Order.new(params [:order])''@ booking.save'。 –

+0

@ErikNomitch你有没有尝试'后(:构建)'回调,而不是'(之前)::?您对“Booking”设置的验证究竟如何?我想这个问题的真正症结在于FactoryGirl可能希望孤立地创建这些对象,这从测试的角度来看是有意义的,但是当您在注释中创建它们时,它们会一起创建。这种耦合通常会导致头痛。 – regulatethis

2

从@ jassa的回答起飞,如果你只需要添加一个(必需的)相关记录与特定的属性,这种模式很适合我:

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