Nathan
Nathan

Reputation: 7855

Factorygirl create complex collection

I have an Item and Category. I want to have multiple Items, each with multiple Categories. I don't want each Item to have different Categories, but rather associate with a common set of Categories.

Is there a way to achieve this using the FactoryGirl dsl?

Here is how I did it using a helper module:

module Features
  module ItemsHelpers
    def create_items_with_categories
      parents = create_list :category, 2
      children = []
      5.times do
        children << (create :category, parent: parents.sample)
      end
      10.times do
        item = build :item
        item.categories << children.sample(3)
        item.save
      end
    end
  end
end

Upvotes: 0

Views: 1499

Answers (1)

Surya
Surya

Reputation: 16012

By looking at the code, I assume, item has many categories:

sequence :name do |n|
  "Item - #{n}"
end

factory :item do
  name { generate(:name) }
  # other fields here..
  ignore do # in the latest version, it is: "transient do.."
    categories_count 5
  end

  after(:create) do |item, evaluator|
    categories { FactoryGirl.create_list(:category, evaluator.categories_count) }
  end
end

You can use this as:

  let(:categories) { create_list(:category, 10) }
  let(:items) { create_list(:item, 5, categories: categories) }

UPDATE: In many cases, when your specs grow, you won't have to be bothered about adding extra: categories while creating items as it'll be created by the default values, unless specified. Hence, ignore/ transient for keeping it classy.

So you can do:

let(:items) { create_list(:items, 10, categories_count: 3) } # when you need just 3 categories per item!!

At the end, it comes down to the preference and the coding structure you follow. I prefer to have both so that I don't have to bother adding categories list when cretaing item or items factory.

Upvotes: 1

Related Questions