2013-06-10 22 views
13

Đây là 2 mô hình đơn giản:FactoryGirl, has_one hiệp hội và xác nhận thất bại

class Post < ActiveRecord::Base 
    has_one :asset, :dependent => :destroy 

    validates :asset, presence: true 
end 

class Asset < ActiveRecord::Base 
    belongs_to :post 
end 

Tôi đang cố gắng để tạo ra một nhà máy như thế này:

factory :post do 
    # fields... 

    asset { FactoryGirl.create(:asset) } 
    end 

    factory :asset do 
    # fields... 

    post 
    end 

Nhưng, chạy spec nó đi vào một vòng lặp .

Tôi cũng đã tryied này:

factory :post do 
    # fields... 

    before(:create) do |post, evaluator| 
     FactoryGirl.create_list(:asset, 1, post: post) 
    end 
    end 

Nhưng kết thúc trong "Xác nhận thất bại: Asset không thể để trống".

Tôi làm cách nào để thể hiện tình trạng của mình?

+0

Có lý do nào bạn đặt 'bài' trên': asset' thay vì cách khác không?Có vẻ kỳ lạ vì 'Post' là cái cần có' Nội dung' trong quá trình tạo. – deefour

+0

Các hiệp hội của nhà máy là dành cho những người nước ngoài và không phải cho các hiệp hội has_one/has_many. Liệu tôi có sai? –

Trả lời

26

Tôi đã giải quyết vấn đề này bằng cách sử dụng sau (: xây dựng) gọi lại.

factory :post do 
    # fields... 
    after(:build) do |post| 
     post.asset ||= FactoryGirl.build(:asset, :post => post) 
    end 
end 

factory :asset do 
    # fields... 
    after(:build) do |asset| 
     asset.post ||= FactoryGirl.build(:post, :asset => asset) 
    end 
end 

Bằng cách này, các đối tượng liên quan sẽ được tạo trước khi lớp sở hữu được lưu, vì vậy hãy xác thực.

+0

gọi lại khác bao gồm 'after (: create)' và 'after (: stub)' được đề cập tại https://robots.thoughtbot.com/aint-no-calla-back-girl – thedanotto

+0

@MichDart Tôi không thể thấy điều này làm việc. Tôi chỉ định nó trong xây dựng gọi lại, in trước khi tạo cuộc gọi trở lại., Đối tượng không có. Nó có được cập nhật không? –

0

Bạn có thể tải trước một hiệp hội trẻ em bằng cách đi qua nó trong như sau:

FactoryGirl.define do 
    factory :post do 
    asset { Asset.create! } 
    end 
end 

(Vẫn còn tốt hơn, sử dụng nhà máy Asset để tạo ra nó liên quan đến tài sản với các chi tiết cài đặt trước).

Cách thủ công khác sẽ là để tạo ra một tài sản qua FactoryGirl.create (: tài sản), và đi qua nó vào việc tạo ra thay đổi, ví dụ:

asset = FactoryGirl.create(:asset) 
post = FactoryGirl.create(:post, asset: asset) 
+0

Cảm ơn, nhưng giải pháp của bạn có tạo ra một nội dung có cùng các trường mà tôi đã xác định trong nhà máy tài sản của tôi không? –

+0

Nếu bạn muốn tạo nội dung có cùng các trường được xác định trong nhà máy sản xuất nội dung của bạn: 'asset {FactoryGirl.create (: asset)}' – HaaR

+0

Vui lòng xem bản cập nhật cuối cùng ở trên ... Tôi vẫn gặp lỗi –

0

lỗi Validation failed: Asset can't be blank là bởi vì nó trông như bạn có sự liên kết ngược trong các nhà máy của bạn.

factory :post do 
    # fields... 
end 

Vì vậy, khi bạn tạo một post không có asset để xác nhận thất bại. Hãy thử điều này

factory :post do 
# fields... 
    asset 
end 

Hãy xem số wiki page and the associations section này. Nó cũng giải thích sự khác biệt giữa createbuild với các liên kết

+1

Tôi đã thử giải pháp đó nhưng không hoạt động. Nó tạo ra một vòng lặp (tôi nghĩ). Bạn đã thử một mình chưa? thanks anyway –

2

Xác thực không thành công vì khi FactoryGirl tạo ra một Post, một nội dung phải có mặt. Vì vậy, trong các định nghĩa FactoryGirl, bạn có thể tạo Asset như một phần của việc tạo một Post. Chèn một cái gì đó giống như file FactoryGirl post.rb:

asset { FactoryGirl.create(:asset) } 

hoặc

Bạn có thể tạo một Asset như một phần của Post khai của bạn trong file spec của bạn như sau:

asset = FactoryGirl.create(:asset) 

FactoryGirl.create(:post, :asset => asset) 

Cảm ơn.

+0

Cảm ơn bạn. Tôi đã cập nhật bài đăng đầu tiên. Nhưng tôi vẫn gặp rắc rối. Bạn có thể giúp tôi được không? –

Các vấn đề liên quan