Never Fear, Traits are Here

I can’t count the number of times I’ve worked on Rails apps where I’m using Factory Girl and want to declare a factory with multiple parents. We’ve all been there, don’t lie.

    FactoryGirl.define do
      factory :user do
        name "Friendly User"

        factory :admin do
          admin true
        end

        factory :male_user do
          gender "Male"
          name   "John Doe"

          factory :male_admin_user do
            admin true
          end

          factory :teenage_male_user do
            date_of_birth { 15.years.ago }

            factory :teenage_admin_male_user do
              admin true
            end
          end
        end

        factory :female_user do
          gender "Female"
          name   "Jane Doe"

          factory :female_admin_user do
            admin true
          end

          factory :teenage_female_user do
            date_of_birth { 15.years.ago }

            factory :teenage_admin_female_user do
              admin true
            end
          end
        end
      end
    end

Oh, the duplication! This isn’t DRY.

Factory Girl 2.0.4 introduces traits. I’ll cut to the chase:

    FactoryGirl.define do
      factory :user do
        name "Friendly User"

        trait :admin do
          admin true
        end

        trait :male do
          gender "Male"
          name   "John Doe"
        end

        trait :female do
          gender "Female"
          name   "Jane Doe"
        end

        trait :teenager do
          date_of_birth { 15.years.ago }
        end

        factory :male_user,                 :traits => [:male]
        factory :female_user,               :traits => [:female]
        factory :teenage_male_user,         :traits => [:teenager, :male]
        factory :teenage_female_user,       :traits => [:teenager, :female]
        factory :male_admin_user,           :traits => [:admin, :male]
        factory :female_admin_user,         :traits => [:admin, :female]
        factory :teenage_admin_male_user,   :traits => [:teenager, :admin, :male]
        factory :teenage_admin_female_user, :traits => [:teenager, :admin, :female]
      end
    end

Mix and match however you please. Bonus: you can assign traits like plain-old attributes.

    FactoryGirl.define do
      factory :user do
        name "Friendly User"

        trait :admin do
          admin true
        end

        trait :male do
          gender "Male"
          name   "John Doe"
        end

        factory :male_admin_user do
          male
          admin
        end
      end
    end

Many props go out to Thomas Walpole, who helped get a lot of this written; thanks Thomas!

So go ahead, get your trait on; you’ll thank me later.

Pair with one of our expert developers to level up your skills with Coaching by thoughtbot. Save time learning best practices and techniques for reducing technical debt in Ember, Ruby, Haskell, and Go in 1-on-1 sessions tailored to your goals.