Home > database >  How to create a FactoryBot factory that is an amalgamation of two other records?
How to create a FactoryBot factory that is an amalgamation of two other records?

Time:07-08

I have an object, let's call it a TransitProvider.

It isn't an ActiveRecord object. It uses ActiveModel but it's designed to pull (or persist) it's data from two separate tables, a Provider table and a TransitService table. (reason being: the concept of "Transit Provider" is a concept that is made up of a Provider that offers a Transit Service).

So this is working well, except when I try to build a Factory (using FactoryBot) for the TransitProvider.

It doesn't have a table, so I can't "create" one. Instead, I'd need to actually create the underlying Provider and TransitService.

But I don't know how to do that in FactoryBot.

I want to be able to do stuff like:

let(:transit_provider) { create(:transit_provider, name: "Some Name") }

and have it "under the covers" actually create the Provider and the TransitService and then populate the ActiveModel TransitProvider with data from both.

Help?!

CodePudding user response:

Thoughtbot recently wrote a blog post on this subject, and FactoryBot's README has a section on creating factories for non-AR Ruby classes. Notably, the implementation relies on initialize_with to instantiate the factory using a custom block, rather than the default behavior of calling new without any arguments on what is assumed to be an AR model.

In your scenario, I would imagine a TransitProvider factory that looks something like:

factory :transit_provider do
  provider { create(:provider) }
  transit_service { create(:transit_service) }

  initialize_with { new(provider, transit_service) }
end

Also important to note that create will never work for the above factory since that attempts to instantiate a model and persist a record in the DB. You'll want to build this factory instead.

  • Related