factory_bot
factory_bot copied to clipboard
Question: Possible to get reference to the build_class from initialize_with?
I'm working with STI and am customizing our initialize_with
block. However, there are some conditions we'd like to put in place that require introspection on the class in question.
It seems there are a number of layers of indirection around the class (decorator, @component, @build_class, etc). Is there a way to get a reference to the factory's class
(essentially new.class
, but without invoking new
) from within the initialize_with
block?
I'd like to bump this questions because I spent a long time digging into this problem before concluding it's just not possible. I'm trying to build a factorybot plugin/integration for an framework we have for managing data from third party api responses. We're using factorybot to build up these non active record data objects which are serialized from the response data. We don't use new
when serializing these objects, so I'd like to be able to have a custom factorybot method that users can add to any factory to indicate this is a "API object factory", and have that method setup the correct initialize_with
block for them. As is the only way I can do that is write a method like this
def api_object_factory(build_class)
initialize_with { build_class.from_hash(attributes) }
end
So users are forced to specific the class twice when defining their factory
factory :api_user, class: "Api::User" do
api_object_factory("Api::User")
end
Would love to make this a little less repetitive
I figured out a way around my particular problem, by doing this
module FactoryHelpers
def api_object_factory(name, options = {}, &block)
raise ArgumentError, "You must specify a class" unless options[:class]
raise ArgumentError, "You must specify a block" unless block
factory(name, options) do
skip_create
initialize_with do
options[:class].constantize.from_hash(attributes)
end
instance_eval(&block)
end
end
end
class FactoryBot::Syntax::Default::DSL
include FactoryHelpers
end
So now consumers don't use the normal factory
method and instead write code like
FactoryBot.define do
api_object_factory(:api_user, class: 'Api::User') {}
This is a fairly reasonable experience in my opinion. But is extending the default DSL a supported extension from the FactoryBot perspective?