Using a 'default' trait in FactoryGirl to avoid unnecessary association creation
Asked Answered
D

3

10

Is it possible to define a default trait in FactoryGirl? If I define a factory like this (where both question_response belongs_to question):

factory :question_response do
  question
  work_history

  trait :open do
    question { FactoryGirl.create :question, question_type: 'open' }
  end
end

When I do FactoryGirl.create :question_response, :open it will first create a default question and then create another inside the trait, which is an unnecessary operation.

Ideally I'd like to do this:

factory :question_response do
  work_history

  trait :default do
    question { FactoryGirl.create :question, question_type: 'yes_no' }
  end

  trait :open do
    question { FactoryGirl.create :question, question_type: 'open' }
  end
end

And then doing FactoryGirl.create :question will use the default trait, but it doesn't seem to be possible.

Dove answered 14/6, 2015 at 13:37 Comment(0)
K
2

When I do FactoryGirl.create :question_response, :open it will first create a default question and then create another inside the trait

It's not true. if you specify the trait with question, it will overwrite the factory behavior before creation so that it does not create a default question.

I checked it with FactoryGirl v4.5.0

Kronick answered 4/2, 2016 at 16:37 Comment(1)
Thanks, you are quite right! I've just verified this myself. I wonder this was added to factory girl recently...Dove
B
1

Just in case someone else is looking for 'default trait' scenario, this was discussed with examples in https://github.com/thoughtbot/factory_bot/issues/528#issuecomment-18289143

Basically, you can define trait with defaults and then use it for different factories. And then you can use appropriate factory with needed configuration.

For example:

FactoryBot.define do
  trait :user_defaults do
    email { Faker::Internet.unique.email }
    username { Faker::Internet.unique.username }
    password { "test1234" }
  end

  factory :with_admin_role, class: User do
    user_defaults

    after(:create) do |user, _|
      user.add_role :admin
    end
  end

  factory :with_readonly_role, class: User do
    user_defaults

    after(:create) do |user, _|
      user.add_role :readonly
    end
  end
end
Bronez answered 1/9, 2020 at 21:53 Comment(0)
W
0

Your trait is creating a 2nd record because you have a block that is creating a record:

trait :open do
  question { FactoryGirl.create :question, question_type: 'open' }
end

Instead, you can do define a trait on question that has the question type set, and then have your question_response use that question with the open trait as its default.

factory.define :question do
  trait :open do
    question_type 'open'
  end
end

factory.define :question_response do
  association :question, :open
end
Works answered 14/9, 2015 at 18:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.