FactoryGirl和协会验证

时间:2015-12-15 08:08:34

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

我有以下工厂设置

FactoryGirl.define do
  factory :image do
    title 'Test Title'
    description 'Test Description'
    photo File.new("#{Rails.root}/spec/fixtures/louvre_under_2mb.jpg")
    after(:build) do
      FactoryGirl.build_list(:category, 1)
    end
  end
end

在我的模型中,我有这些验证

class Image < ActiveRecord::Base
  has_many :categories
  validates :title, presence: { message: "Don't forget to add a title" }
  validates :description, presence: { message: "Don't forget to add a description" }
  validates :categories, presence: { message: 'Choose At Least 1 Category' }
end

当我运行此测试时,它失败

RSpec.describe Image, type: :model do
  it 'should have a valid Factory' do
    expect(FactoryGirl.build(:image)).to be_valid
  end
end

Failure/Error: expect(FactoryGirl.build(:image)).to be_valid
expected #<Image id: nil, title: "Test Title", description: "Test Description", photo_file_name: "louvre_under_2mb.jpg", photo_content_type: "image/jpeg", photo_file_size: 65618, photo_updated_at: "2015-12-15 08:01:07", created_at: nil, updated_at: nil> to be valid, but got errors: Categories Choose At Least 1 Category

我是否接近这个错误,因为我认为在整个对象创建之前验证不会启动?还是我错误地想到了这个?

由于

2 个答案:

答案 0 :(得分:2)

问题出在这一部分。

after(:build) do
  FactoryGirl.build_list(:category, 1)
end

这将创建大小为1的类别列表,但这些类别不与图像对象相关联。正确的方法如下:

transient do
  categories_count 1
end
after(:build) do |image, evaluator|
  image.categories = build_list(:category, evaluator.categories_count)
end

transient do
  categories_count 1
end
categories { build_list(:category, categories_count) }

就个人而言,我会选择最后一个选项。

photo属性也是有问题的。 FactoryGirl是关于创建记录的灵活性。但是您使用它的方式不会提供任何灵活性,因此照片属性将在您使用此工厂创建的所有记录之间共享。你迟早会面临一些麻烦。

因此,创建photo属性的正确方法如下:

transient do
  photo_name 'default_photo.jpg'
end
photo { File.new(File.join(Rail.root, "spec/fixtures", photo_name) }

比你可以这样使用

FactoryGirl.build(:image, photo_name: 'new_photo_name.jpg')

答案 1 :(得分:0)

我建议不要在图片工厂中使用after方法。您应该创建正确的关联。使用此功能,您将解决验证错误,并且将来不会遇到其他问题。

class Image
  accepts_nested_attributes_for :categories
end

FactoryGirl.define do
  factory :image do
    categories_attributes { [FactoryGirl.attributes_for(:category)] }
  end
end