class FactoryBotCaching::FactoryCache
Attributes
Public Class Methods
# File lib/factory_bot_caching/factory_cache.rb, line 29 def initialize(factory_name:) @factory_name = factory_name @build_class = FactoryGirl.factory_by_name(factory_name).build_class @cache = new_cache(@build_class) @cachable_overrides = [] collect_uncachable_traits end
Public Instance Methods
# File lib/factory_bot_caching/factory_cache.rb, line 39 def fetch(overrides:, traits:, &block) key = { overrides: overrides, traits: traits} if should_cache?(key) cache.fetch(key, &block) else block.call end end
# File lib/factory_bot_caching/factory_cache.rb, line 48 def reset @cache = new_cache(build_class) end
# File lib/factory_bot_caching/factory_cache.rb, line 52 def reset_counter cache.reset_counters end
Private Instance Methods
Determine whether or not an overridden value in a factory call is cacheable. We use some caching and perform comparisons in order of probability which nets a 70x improvement in performance over previous versions of this validation.
For example:
FactoryGirl.create(:customer, name: 'John Doe', email: 'john.doe@example.test') FactoryGirl.create(:customer, name: 'John Doe', address_id: 123)
In the above examples, `address_id` is a passed in association and should not be cached.
@param override_sym [Symbol] @return [Boolean] true if the overridden value is cacheable, false otherwise
# File lib/factory_bot_caching/factory_cache.rb, line 105 def cacheable_override?(override_sym) # Search in order of probability to reduce lookup times: return true if cachable_overrides.include?(override_sym) return false if common_associations.include?(override_sym) return false if uncommon_associations.include?(override_sym) cachable_overrides << override_sym true end
Collect a list of traits that are considered 'uncachable' if passed in the overrides list. We collect two lists - belongs_to associations, which have a high probability to be overridden in a factory call and should be compared against first, followed by uncommon_associations
# File lib/factory_bot_caching/factory_cache.rb, line 73 def collect_uncachable_traits return unless build_class < ActiveRecord::Base @common_associations = [] @uncommon_associations = [] reflections = build_class.reflect_on_all_associations reflections.each do |reflection| if reflection.macro == :belongs_to @common_associations << reflection.name.to_sym # In rails land, some foreign keys are symbols, some strings; coerce them here: @common_associations << reflection.foreign_key.to_sym else @uncommon_associations << reflection.name.to_sym end end end
# File lib/factory_bot_caching/factory_cache.rb, line 60 def new_cache(build_class) if FactoryBotCaching.configuration.custom_cache_key.nil? FactoryRecordCache.new(build_class: build_class) else CustomizedCache.new( build_class: build_class, cache_key_generator: FactoryBotCaching.configuration.custom_cache_key) end end
Skip caching for factories that are called with passed in associations, as it mutates the association and persisted record
# File lib/factory_bot_caching/factory_cache.rb, line 115 def should_cache?(key) return false unless build_class < ActiveRecord::Base key[:overrides].all? do |key, v| cacheable_override?(key.to_sym) end end