Let's just say FactoryGirl doesn't have a feature like this for a reason. If you're running into a situation where, for example, tests are failing because your database is throwing uniqueness constraint errors, you've probably done something wrong. You should stop reading this and go fix it properly.
If you're still here, then I've got a janky and brittle (read: epic) solution for you! To illustrate:
module FactoryGirlHelper BLACKLIST = [:user] def first(args) name = args.first klass = name.to_s.camelize.constantize conditions = args.last if conditions.present? && conditions.is_a?(Hash) klass.where(conditions).first end end def first_or_create(*args) result = first(args) if BLACKLIST.include?(args.first) result || FactoryGirl.create(*args) end end
This helper implements a first_or_create call and attempts to find an object matching the parameters passed in. It only calls FactoryGirl's create if the where returns an empty relation, or if the model being created is not in the BLACKLIST. Disclaimer: this is not going to work with traits. Don't forget to include the helper in your RSpec config:
# In rails_helper.rb RSpec.configure do |config| config.include FactoryGirlHelper end
Let's write a test for this functionality and make sure it works:
require 'rails_helper' RSpec.describe FactoryGirlHelper do subject do first_or_create(:user, first_name: 'Donald', last_name: 'Trump') first_or_create(:user, first_name: 'Donald', last_name: 'Trump') end it 'I am the only one who can make this app great again' do expect(FactoryGirl).to receive(:create).once.and_call_original subject end end # Output 1/1 |========================= 100 ==========================>| Time: 00:00:03 Top 1 slowest examples (1.29 seconds, 53.3% of total time): FactoryGirlHelper I am the only one who can make this app great again 1.29 seconds ./spec/helpers/factory_girl_helper_spec.rb:9 Finished in 2.41 seconds (files took 0.76389 seconds to load) 1 example, 0 failures
Of course it works! Now, your flaky test suite has an extra band-aid that will keep it running for at least another few days. It's very important to remember that this is a Trump solution, so now your app will only get worse and you'll have even more tech debt to default on, but you will also have the world's greatest app. It's a fantastic app, by the way. Everyone agrees that your app is fantastic.