2014-01-21 94 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。