graial
graial

Reputation: 79

defined STI relationships fail in FactoryBot/lint

Hi there, I have the following 3 models:

Location < ApplicationRecord

StagingLocation < Location

Package < ApplicationRecord belongs_to :location

I can set-up associations to create a valid Package factory by simply calling the factory of the StagingLocation instead of the Location. As per the following code:

package_spec.rb:

  describe "package validation" do
let(:package_location) { create(:staging_location) }
it "has a valid factory" do
  expect( create(:package, location: package_location) ).to be_valid
end

However, this will not pass FactoryBot.lint

1. lint throws an error on the creation of a Location

FactoryBot.define do
  factory :location do
  type { "StagingLocation" }
  name { "Location" + Faker::GreekPhilosophers.unique.name }    
  end
end

throws this error

The single-table inheritance mechanism failed to locate the subclass: '0'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite Location.inheritance_column to use another column for that information. (ActiveRecord::SubclassNotFound)

2. Calling the staging_location factory fails with a

NoMethodError

because Package is looking for a location

FactoryBot.define do
  factory :package do
    staging_location
    name { "TEST-" + rand(99).to_s }
  end
end

I see three possible ways to get around this but can't seem to find FactoryBot syntax to accomplish them:

a) Create a Location factory

b) Create a StagingLocation factory that returns a Location class using the base_class method or similar

c) Tell the Package factory to accept the staging_location as a location factory

d)Ignore the error since at the end of the day, my factories are being created as expected.

Any suggestions?

Upvotes: 0

Views: 706

Answers (1)

graial
graial

Reputation: 79

As per this issue on the FactoryBot github page,

STI can be defined by declaring the child factory within the parent factory and declaring the STI class.

In my case this worked out as follows:

FactoryBot.define do
  factory :location, class: "StagingLocation" do
    name { "Staging " + rand(99).to_s }    
  end
end

FactoryBot.define do
  factory :package do
    name { "Package " + rand(99).to_s }    
    location { create(:staging_location, location: location) }
  end
end

Upvotes: 0

Related Questions