我是FactoryGirl的新手,在Ruby中,我正在尝试编写一些rspec但是我遇到了一些循环依赖的麻烦。我搜索并尝试了几个东西,最后一个产生了无限循环,我不得不关闭我的WM。 (proc 100%)
模型/投票
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都包含其父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找到了一个关于“如何在&gt; 3.3中使用after_create”的教程,但它对我不起作用,我不应该得到“投票选项不能为空”...所以我拿了一个查看上一个链接中链接的文档,我尝试添加 spec / factories
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 :(得分:1)
您是否曾尝试根据document的 Association 章节进行操作?
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
工厂必须定义为单个,而不是复数。
答案 1 :(得分: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。