Hi. I am travis and I work in a place long ago abandoned by the gods: New York City. By day, I am a Software Engineer at Patreon. By night, i am a normal person.

FactoryGirl First Or Create

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.

Intro to Avro

RSpec Search & Destroy