Reputation: 15374
I have the following factory setup
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
Within my model i have these validations
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
When I run this test it fails
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
Am i approaching this wrong as i was thinking that the validations would not kick in until the whole object was created? or am i thinking about this incorrectly ?
Thanks
Upvotes: 1
Views: 193
Reputation: 2359
the problem is in this part.
after(:build) do
FactoryGirl.build_list(:category, 1)
end
this will create a list of categories of size 1, but those categories are not associated to the image object. The proper way is as follows:
transient do
categories_count 1
end
after(:build) do |image, evaluator|
image.categories = build_list(:category, evaluator.categories_count)
end
or
transient do
categories_count 1
end
categories { build_list(:category, categories_count) }
personally, I would choose this last option.
the photo
attribute as well is problematique. FactoryGirl is all about flexibility of creating records. But the way you're using it will not present any flexibility, so the photo attribute will be shared between all the records that you'll create using this factory. And sooner or later you'll face some headaches.
so the proper way of creating the photo
attribute is as follows.
transient do
photo_name 'default_photo.jpg'
end
photo { File.new(File.join(Rail.root, "spec/fixtures", photo_name) }
than you can use it this way
FactoryGirl.build(:image, photo_name: 'new_photo_name.jpg')
Upvotes: 2
Reputation: 3869
I would recommend don't use after
method in image factory. You should create a correct association. Using this you'll resolve validation error and will't have others problems in the future.
class Image
accepts_nested_attributes_for :categories
end
FactoryGirl.define do
factory :image do
categories_attributes { [FactoryGirl.attributes_for(:category)] }
end
end
Upvotes: 0