Validating That A has_many Association Has At Least One Model When Using FactoryGirl
Asked Answered
V

1

8

Putting aside arguments on whether or not you should test existence of a model's associations, I have a model called Order and I am validating that it has at least one item in its has_many association using:

class Order < ActiveRecord::Base

  has_many :items

  validates :items, presence: true

end

I have set FactoryGirl to lint my factories (checking for validity). So my order factory is not valid unless I create an item for its has_many collection.

My orders factory looks like this:

FactoryGirl.define do

  factory :order do

    ignore do
      items_count 1
    end

    after(:build) do |order, evaluator|
      create_list(:item, evaluator.items_count, order: order)
    end

  end
end

According to Factory Girl's Getting Started:

FactoryGirl.lint builds each factory and subsequently calls #valid? on it

However when I run my specs, Factory Girl throws an FactoryGirl::InvalidFactoryError because the order factory is invalid.

Workaround

after(:build) do |order, evaluator|
   evaluator.items_count.times do
     order.items << FactoryGirl.create(:item)
   end
   #create_list(:item, evaluator.items_count, order: order)
 end
Velda answered 20/6, 2014 at 14:7 Comment(9)
You're doing a create_list(:item), do you have item factory defined?Neustria
Yes. The item factory is there and is valid.Velda
I think you should be using after(:create) instead of after(:build) for this because with just build the order is not saved and there is no order_id for items.Neustria
@Neustria but if it validates the presence of at least one item, how can it be created without one?Velda
I think validates :items, presence: true check if items.present? returns true/false. order.items returns [] for new object. [].present? returns true. So validation passes correctlyCountrywoman
@Countrywoman [].present? does not return true.Gravamen
@Pedr In your workaround, did you mean order.items << FactoryGirl.create(:item, order: order), or are you relying on the item factory to create a different order? Does an item have one or many orders?Gravamen
oh, about [].present? # => true I am wrong. I recheck Rails 4.1.1 works as expected and validation failed - record is invalid without items. Maybe Rails version is important for this stuff.Countrywoman
Does it work if you use build_list instead of create_list?Halyard
H
1

According to the definition, it will call .valid? AFTER building. It seems that it will call this before running the after(:build) block.

Try writing you factory like this:

FactoryGirl.define do

  factory :order do

    ignore do
      items_count 1
    end

    items { build_list(:item, items_count) }

  end
end

This should build the item before the .valid? is called.

Let me know if this works :)

Heterogeneity answered 12/5, 2015 at 8:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.