Creating custom-class objects with factory_bot
Hey guys,
I'm trying to upgrade our contentful gem to the most recent version. We are currently still on 0.8. Our test-suite relies on being able to create instances of custom Contentful-class via factory_bot.
Here is an example configuration of a factory:
FactoryBot.define do
factory :category, class: Contentful::Category do
title { FFaker::DizzleIpsum.word }
slug { FFaker::Internet.slug.delete(".") }
end
end
whereas Contentful::Category looks like:
class Contentful::Category < Contentful::Entry
...
end
and is mentioned in the entry_mapping.
Since upgrading to 2.15.3 I have to give factory_bot an initialize_with-methode since Content::FieldsResource requires itemand configuration as parameters (https://github.com/contentful/contentful.rb/blob/66961c154632c67bac87fbc395d1580b57a872f2/lib/contentful/fields_resource.rb#L12)
But initialize_with({},{}) won't do and then I'm in the process of reconstructing real-world contentful-API-responses.
Is there a good way to quickly create instances of Contentful-Custom-Classes without the whole enchilada?
@dlitvakb We solved this once waaaay back when https://github.com/contentful/contentful.rb/issues/79 ;-)
OK, I have a temporary (very ugly) solution like this.
Create a new super-class for all you Contentful::Entrys.
Mine is called Contentful::BaseEntry.
Then do this:
# frozen_string_literal: true
class Contentful::BaseEntry < Contentful::Entry
def initialize(*_args)
if Rails.env.test?
enabled_factory_bot_object_creation!
else
super
end
end
def enabled_factory_bot_object_creation!
@raw = {}
@default_locale = "de-DE"
@depth = 0
@configuration = {}
@sys = { "id" => SecureRandom.hex(8) }
@localized = false
@fields = {}
def content_type_field?(_name)
false
end
def repr_name
"#{self.class}[#{sys['id']}]"
end
def method_missing(name, *args)
if name.to_s.ends_with?("=")
field_name = name.to_s[0..-2]
@fields[field_name] = args[0]
else
@fields[name.to_s]
end
end
def respond_to_missing?(name, _include_private = false)
(name.to_s.ends_with?("=") || @fields.keys.include?(name.to_s))
end
end
end
Now, if you have a Contentful::Article like so:
class Contentful::Article < Contentful::BaseEntry
end
You'll be able to create object with factory_bot like so:
FactoryBot.define do
factory :article, class: Contentful::Article do
title { FFaker::DizzleIpsum.word }
end
end
Still thinking about, if this is doable in a more clean way...