Reputation: 3928
For the sake of example, I have a model for chemical elements
class Element < ActiveRecord::Base
validates :name, presence: true, uniqueness: true
validates :symbol, presence: true, uniqueness: true
end
In seeds.rb
I define all the known elements
Element.where(name: "hydrogen" symbol: "H").first_or_create
...
Element.where(name: "ununoctium" symbol: "Uuo").first_or_create
I define a factory
FactoryGirl.define do
factory :element do
name "hydrogen"
symbol "H"
end
end
Since the codebease depends on the presence of all seed elements, I prepare the test database with
rake db:seed RAILS_ENV=test
Now my factory will never work
FactoryGirl.create(:element) #=> validation failed error
How do I write a factory in a way that first tries to find the creatable object in the database?
FactoryGirl.create(:element) #=> returns Element from db || Factory invocation
Upvotes: 2
Views: 579
Reputation: 3928
For sake of posterity, answering my own question with half a decade of experience under the belt.
Try using FactoryBot's initialize_with
hook as described in docs.
factory :element do
initialize_with do
where(name: name, symbol: symbol).first_or_initialize
end
name "hydrogen"
symbol "H"
end
A spin on the idea is to forego the general factory and only have named factories for countable, uniqueness-constrained resources like chemical elements:
factory :element_hydrogen do
initialize_with do
where(name: "hydrogen", symbol: "H").first_or_initialize
end
end
Upvotes: 2
Reputation: 798
Why not doing this:
element = Element.find_by(name: "hydrogen") || FactoryGirl.create(:element, name: "hydrogen", symbol: "H")
Upvotes: 0