Search code examples
ruby-on-railsrubyactiverecordfactory-bot

FactoryBot namespaced models without class_name


I have models which are namespaced such as this:

class Vehicle < ActiveRecord::Base; end

class Vehicle::Car < Vehicle; end
class Vehicle::Train < Vehicle; end
class Vehicle::Jet < Vehicle; end

When creating factories for these models, they were set up in the following way:

factory :vehicle_car, class: Vehicle::Car do; end
factory :vehicle_train, class: Vehicle::Train do; end
factory :vehicle_jet, class: Vehicle::Jet do; end

This produces the following deprecation warning:

DEPRECATION WARNING: Looking up factories by class is deprecated and will be removed in 5.0. Use symbols instead and set FactoryBot.allow_class_lookup = false.

Is there a format for writing a symbol to name these factories such that I do not need to use the class name to comply with the deprecation warning?


Solution

  • The documentation wasn't terribly useful as to how the :class option behaves or what it expects as its value but the source was more helpful. Backtracking from the error message we find FactoryBot::Decorator::ClassKeyHash#symbolize_keys:

    def symbolized_key(key)
      if key.respond_to?(:to_sym)
        key.to_sym
      elsif FactoryBot.allow_class_lookup
        ActiveSupport::Deprecation.warn "Looking up factories by class is deprecated and will be removed in 5.0. Use symbols instead and set FactoryBot.allow_class_lookup = false", caller
        key.to_s.underscore.to_sym
      end
    end
    

    The key.to_sym in the first branch is the usual idiom for "I want a Symbol or String". The key.to_s.underscore.to_sym in the second branch tells us what format is expected.

    If you run Vehicle::Car through to_s.underscore, you get 'vehicle/car' so these should work:

    factory :vehicle_car,   class: 'vehicle/car'   do; end
    factory :vehicle_train, class: 'vehicle/train' do; end
    factory :vehicle_jet,   class: 'vehicle/jet'   do; end
    

    or if you really want Symbols (or have a thing for punctuation):

    factory :vehicle_car,   class: :'vehicle/car'   do; end
    factory :vehicle_train, class: :'vehicle/train' do; end
    factory :vehicle_jet,   class: :'vehicle/jet'   do; end