Sam
Sam

Reputation: 1253

How can I add a function to FactoryBot globally?

I have a class that extends FactoryBot to include functionality to copy Rails' .first_or_create.

module FactoryBotFirstOrCreate
  def first(type, args)
    klass = type.to_s.camelize.constantize

    conditions = args.first.is_a?(Symbol) ? args[1] : args[0]

    if !conditions.empty? && conditions.is_a?(Hash)
      klass.where(conditions).first
    end
  end

  def first_or_create(type, *args)
    first(type, args) || create(type, *args)
  end

  def first_or_build(type, *args)
    first(type, args) || build(type, *args)
  end
end

I can add that to the SyntaxRunner class

module FactoryBot
  class SyntaxRunner
    include FactoryBotFirstOrCreate
  end
end

to access it in factories

# ...
after(:create) do |thing, evaluator|
  first_or_create(:other_thing, thing: thing)
end

But when I attempt to employ this outside of factories, I can't access it...

With all of those steps in place, I still get NoMethodError: undefined method first_or_create

What can I include or otherwise configure to allow this method to be as accessible to me as FactoryGirl's create?

Upvotes: 1

Views: 1864

Answers (2)

Chiperific
Chiperific

Reputation: 4696

This worked for me in an initializer file:

module SystemRecords
  def system_authentication_user
    AuthenticationUser.system
  end

  def system_platform_tenant
    PlatformTenant.system
  end

  def system_user_profile
    UserProfile.admin_role
  end

  def system_user
    User.system
  end
end

module FactoryBot
  class SyntaxRunner
    include SystemRecords
  end
end

I could now do:

FactoryBot.define do
  factory :some_record, class: SomeClass do
    platform_tenant { system_platform_tenant }
    created_by { system_user_profile }
    updated_by { created_by }
    authentication_user { system_authentication_user }
  end
end

Upvotes: 0

Sam
Sam

Reputation: 1253

Per @engineersmnky, extending FactoryBot works

module FactoryBot
  extend FactoryBotFirstOrCreate
end

then this works

my_foo = first_or_create(:everything, is: :awesome, if_we: :work_together)

Upvotes: 0

Related Questions