factory_bot
factory_bot copied to clipboard
`modify` doesn't allow changing the class
Description
FactoryBot.modify
doesn't allow changing a factory's class. It's not explicitly mentioned in the docs, so this could reasonably be classified as a feature request. Though I rather expected it to be possible.
Reproduction Steps
Given:
class Test; end
class TestNew; end
FactoryBot.define do
factory :test do; end
end
FactoryBot.modify do
factory :test, class: "TestNew" do; end
end
Expected behavior
I expected FactoryBot.build :test
to return an instance of TestNew
.
Actual behavior
[2] pry(main)> FactoryBot.build :test
=> #<Test:0x00007fe87d6c1ed0>
System configuration
factory_bot version: 5.1.1 rails version: 6.0 ruby version: 2.6.5
Rationale
I'm sure this probably seems like an odd thing to do. Here's the scenario: We are migrating models from a legacy database, so we have the legacy db models defined is Legacy::MyRecord
where each (or most) of the legacy models has a corresponding MyRecord
(no-namespace) which lives in the new database. The application code (including the existing factories) all reference Legacy::*
.
We are using a feature flag to allow the code to run where each Legacy::*
constant is instead redefined to be the new class. (We're using class Legacy::Foo < Foo
to keep AR happy.) However, factory bot (and active record's) introspection doesn't allow the constant redefinition to "just work". For the AR associations to work, the factory bot factory needs to be of the right class.
There are dozens of legacy models to be migrated, which means dozens of factories that we'd prefer not to duplicate. The hope was that we could use .modify
to change each factory's class
when the feature flag is enabled. But this appears to have no effect.
@jasonkarns I took an initial swing at this and I'm not sure how feasible this is from the feature request side. You might be better off using explicit class definition on all Factories and conditionally defining the class by the Feature Flag.
class Test; end
class TestNew; end
FactoryBot.define do
factory :test, class: (feature_flag == 'legacy') ? "Test" : "TestNew" ; end
end