to_create has either arity of one - to_create {|instance| do something } or two to_create {|instance, context| do something with instance and context }
For the context, we are using repository pattern in our app, the entities are immutable structs, so building them is simply initializing a class. Same time persistence is a create(**attrs) method in a repo instance, that returns an entity after saving it to a DB.
This is the snippet I've came up with after some experimenting:
module FactoryBotHelpers
# no clean way (only chain of private methods and vars) to pass our repo class to both initialize_with and to_create
# custom strategies also don't provide access to the class of the factory for some reason
# hence, this helper method
def factory(name, repo_class:, &)
# values that are mandatory to initialize our immutable entities,
# but are set in most cases by ORM when persisting
missing_build_attributes = {
id: -> { GenerateULID.call },
}
FactoryBot.define do
# expectation was that class won't be required as we are overriding initialize_with
# but FactoryBot still tries to figure out class name from factory name
factory name, class: repo_class do
initialize_with do
repo_class.constantize.new.entity_class.new(
**missing_build_attributes.transform_values(&:call),
**attributes,
)
end
to_create do |instance, context|
repo_class.constantize.new.create!(
**instance.attributes.except(
# we need to remove default values that we supplied in initialize_with, but
# we also need to keep the values that were set by the test
missing_build_attributes.keys - context.__override_names__,
),
)
end
instance_eval(&)
end
end
end
module_function :factory
end
But in this case requires access to the names of the overridden attributes via __override_names__. Is it discouraged?
to_create
has either arity of one -to_create {|instance| do something }
or twoto_create {|instance, context| do something with instance and context }
For the context, we are using repository pattern in our app, the entities are immutable structs, so building them is simply initializing a class. Same time persistence is a
create(**attrs)
method in a repo instance, that returns an entity after saving it to a DB.This is the snippet I've came up with after some experimenting:
But in this case requires access to the names of the overridden attributes via
__override_names__
. Is it discouraged?