2014-01-21 75 views
0

我是新的FactoryGirl,在Ruby中,我試圖寫一些rspec,但是我得到了一些循環依賴的麻煩。我搜索並嘗試了幾件事,最後一件產生了一個無限循環,我不得不關閉我的WM。 (PROC 100%)FactoryGirl循環依賴和驗證

模型/投票

class Vote < ActiveRecord::Base 
    has_many :vote_options 

模型/ vote_option

class VoteOption < ActiveRecord::Base 
    belongs_to :vote 
    accepts_nested_attributes_for :vote_options, reject_if: :all_blank 

規格/模型/ vote_spec

describe Vote do 
    describe 'should return the good label' do 
    let(:nobody) { FactoryGirl.create(:vote, visibility: 0) } 
    it "should not be visible" do 
     nobody.intercom_custom_data[:visibility].should == I18n.t("votes.new.visibility_none") 
    end 
    end 
end 

規格/工廠

factory :vote do 
    team 
    question 'Question?' 
    question_type 0 

    # Avoid validation because of the circular dependency. 
    # https://stackoverflow.com/questions/9322353/factory-girl-create-that-bypasses-my-model-validation 
    after(:build) do |vote| 
     vote.vote_options << VoteOption.create(vote_id: vote.id) 
     #vote.save!(:validate => false) 
    end 
    end 

    factory :vote_allowed do 
    user 
    vote 
    allowed 1 
    end 

    factory :vote_casted do 
    vote_allowed 
    vote_options 
    end 

    factory :vote_options do 
    vote 
    title 'default option' 
    end 

這是做了一個無限循環的代碼。我猜想它由於循環依賴性而無限地創建了投票和vote_options。

所以,我得到了一個有很多vote_options(用戶選擇)的投票,每個vote_options都包含它的父id。如果字段爲空,驗證會拒絕創建,但我們沒有此代碼的問題來保存新投票/ vote_options,因爲所有內容均在同一個事務中完成。

但是,與rspec,我不能創建在同一時間投票和一個vote_options行取決於對方。 (或者我不知道該怎麼做)

所以,我試圖避免這樣的驗證:

after(:create) do |vote| 
    VoteOption.create(vote_id: vote.id) 
    vote.save!(:validate => false) 
end 

但我得到了一個錯誤:

Failure/Error: let(:nobody) { FactoryGirl.create(:vote, visibility: 0) } 
ActiveRecord::RecordInvalid: 
    Validation failed: Vote options can't be blank 

我試着之前使用after_create而不是after(:create),但是我的FactoryGirl在4.3中,所以after_create不再存在。我在https://stackoverflow.com/questions/15003968/undefined-method-after-create-with-factorygirl找到了關於「如何在3.3中使用after_create」的教程,但它不適用於我,我不應該得到「投票選項不能爲空」......所以我看了一下鏈接的文檔在以前的鏈接,我試圖在規範添加/工廠

FactoryGirl.define do 
    after(:create) {|instance| instance.create } 

但我真的不明白我應該做的,我不明白問題出在哪裏。任何想法?

編輯#1:

factory :vote do 
    team 
    question 'Question?' 
    question_type 0 

    association :vote_options, factory: :vote_options 
    # tried with :create and :build 
    after(:create) do |vote, evaluator| 
     create_list(:vote_options, 1, vote: vote) 
    end 
    end 
+0

你的規格觸發這個問題是什麼樣的? –

+0

我不清楚這個問題。其他規格我沒有問題。這裏的問題是因爲模型的設計方式,具有循環依賴性,並且由於驗證拒絕創建新實例(如果字段爲空),所以我需要避免驗證。我用'vote.save!(:validate => false)'做了它,它似乎工作,因爲我沒有得到空白字段「,但我得到了」after_create不是函數「,所以我用」after (:創建)「,但我再次得到了」空白領域「,所以我不知道什麼在這裏不起作用。 – Vadorequest

+0

你爲什麼不使用* factorygirl * association? –

回答

1

您是否嘗試根據document協會章呢?

ignore do 
    vote_options_count = 1 
end 

after(:build) do | vote, evaluator | 
    create_list(:vote_option, evaluator.vote_options_count, vote: vote) 
end 

之後,它應該被允許訪問如下:

create(:vote).vote_options.length # 0 
create(:vote, vote_options_count: 15).vote_options.length # 15 

:本vote_option工廠必須定義爲一個單一的,而不是多個箱子。

+0

但我無法定義vote_options之前,它也需要投票來定義... ^^' – Vadorequest

+0

@Vadorequest爲什麼你不能shell來定義'vote_option' - 單一,而不是複數? –

+0

也許你是對的,所以在factories.rb我改變vote_options投票選項,但我得到了:失敗/錯誤:無法找到匹配線回追 SystemStackError: 堆棧級別太深 – Vadorequest

0

我不喜歡針鋒相對:

規格/工廠

factory :vote_option do 
    vote 
    title 'default option' 
    end 

    factory :vote do 
    team 
    question 'Question?' 
    question_type 0 
    vote_options_attributes {[{ 
     title: 'foo' 
    }]} 
    end 

    factory :vote_allowed do 
    user 
    vote 
    allowed 1 
    end 

    factory :vote_casted do 
    vote_allowed 
    vote_option 
    end 

規格/型號/ vote_spec

describe Vote do 

    describe 'should return the good label' do 
    let(:nobody) { FactoryGirl.create(:vote, visibility: 0) } 

    it "should not be visible" do 
     #nobody.intercom_custom_data[:visibility].should == I18n.t("votes.new.visibility_none") 
     puts nobody.inspect 
     puts nobody.vote_options.inspect 
    end 

    end 
end 

控制檯

Run options: exclude {:semaphore_ignore=>true} 
#<Vote id: 1, users_id: nil, teams_id: 1, datetime: "2014-01-21 13:42:37", question: "Question?", question_type: 0, not_vote: 0, hidden: nil, visibility: 0> 
[#<VoteOption id: 1, vote_id: 1, title: "foo", votes: 0, created_at: "2014-01-21 12:42:37", updated_at: "2014-01-21 12:42:37">] 

我不使用任何關聯,任何名單,我只是強制添加options_attributes自動創建創建投票時vote_options。 (就像我們在瀏覽器創建新投票時那樣)

謝謝majioa。