FactoryGirl,has_one关联和验证失败

时间:2013-06-10 23:29:48

标签: ruby-on-rails rspec factory-bot

这是两个简单的模型:

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

  validates :asset, presence: true
end

class Asset < ActiveRecord::Base
  belongs_to :post
end

我正在尝试创建这样的工厂:

  factory :post do
    # fields...

    asset { FactoryGirl.create(:asset) }
  end

  factory :asset do
    # fields...

    post
  end

但是,运行规范会进入循环。

我也试过这个:

  factory :post do
    # fields...

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

但结果是“验证失败:资产不能为空”。

我如何表达我的情况?

4 个答案:

答案 0 :(得分:30)

我使用after(:build)回调解决了这个问题。

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

通过这种方式,将在保存拥有类之前创建关联对象,因此验证通过。

答案 1 :(得分:2)

验证失败,因为当FactoryGirl创建Post时,必须存在资产。因此,在您的FactoryGirl定义中,您可以创建Asset作为创建Post的一部分。插入类似FactoryGirl post.rb文件的内容:

asset { FactoryGirl.create(:asset) }

您可以在规范文件中创建Asset声明作为Post声明的一部分,如下所示:

asset = FactoryGirl.create(:asset)

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

感谢。

答案 2 :(得分:0)

您可以通过以下方式传递子协会来预加载:

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

(更好的是,使用资产工厂生成相关资产并预先设置详细信息。)

另一种手动方式是通过FactoryGirl.create(:asset)创建一个Asset,并将其传递给变量创建,即:

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

答案 3 :(得分:0)

错误Validation failed: Asset can't be blank是因为看起来你的工厂后面有关联关系。

factory :post do
  # fields...
end

因此,当您创建post时,没有asset,因此验证失败。试试这个

factory :post do
# fields...
  asset
end

看看这个wiki page and the associations section。它还解释了createbuild之间的区别