FactoryGirl使用has_many关联创建额外记录

时间:2014-04-20 17:14:51

标签: ruby-on-rails ruby rspec factory-bot

我遇到了FactoryGirl似乎正在创建具有has_many关系的额外记录的问题。

鉴于这些模型:

class NextAction < ActiveRecord::Base
  has_many :next_actions_orders
  has_many :orders, through: :next_actions_orders
end

class NextActionsOrder < ActiveRecord::Base
  belongs_to :order
  belongs_to :next_action
end

class Order < ActiveRecord::Base
  has_many :next_actions_orders
  has_many :next_actions, through: :next_actions_orders
end

这些工厂:

FactoryGirl.define do
  factory :next_action do
    status :pending

    trait :pickup do
      next_actions_orders { FactoryGirl.create_list(:next_actions_order, 1) }
      action_type :pickup
    end

    trait :multiple_pickups do
      next_actions_orders { FactoryGirl.create_pair(:next_actions_order) }
      action_type :pickup
    end
  end
end

FactoryGirl.define do
  factory :next_actions_order do
    order { FactoryGirl.create(:order) }
    next_action
  end
end

FactoryGirl.define do
  factory :order do
    status :pending
  end
end

正如您在NextAction工厂中看到的,我遇到了设置NextActionOrder关联的问题。

我通常使用next_actions_orders { FactoryGirl.create(:next_actions_order) },但使用has_many :next_actions_orders,我收到了undefined method 'each' for #<NextActionsOrder...错误。

next_actions_orders { FactoryGirl.create_list(:next_actions_order, 1) }似乎可以解决这个问题。如下所示,这似乎不是问题的原因,因为它也存在于create_pair示例中。

真正的问题是:

it 'create_list generates duplicate FactoryGirl records' do
  puts NextAction.count # output: 0

  pickup = create(:next_action, :pickup)

  puts NextAction.count # output: 2

  ## binding.pry
end

简洁地说,create(:next_action)调用似乎产生了1个额外的NextAction记录。

我用撬检查这一点,果然,你可以看到这一点。

在上面显示的第一个位置插入pry,查询产生以下内容:

pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextAction.all
=> [#<NextAction id: 2, ... created_at: "2014-04-20 16:40:57", updated_at: "2014-04-20 16:40:57", status: 0>,
 #<NextAction id: 3, ... created_at: "2014-04-20 16:40:57", updated_at: "2014-04-20 16:40:57", status: 0>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextActionsOrder.all
=> [#<NextActionsOrder id: 1, next_action_id: 3, order_id: 2>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> Order.all
=> [#<Order id: 2, created_at: "2014-04-20 16:40:57", updated_at: "2014-04-20 16:40:57", status: 0>]

除了NextAction ID#2之外,一切看起来都很棒。它没有任何关联,它只是因某种原因而创建的孤儿记录。

以下是create_pair

的情况
it 'create_pair generates duplicate FactoryGirl records' do
  puts NextAction.count # output: 0

  pickups = create(:next_action, :multiple_pickups)

  puts NextAction.count # output: 3

  ## binding.pry
end

如图所示插入pry,相同的查询产生:

pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextAction.all
=> [#<NextAction id: 4, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>,
 #<NextAction id: 5, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>,
 #<NextAction id: 6, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextActionsOrder.all
=> [#<NextActionsOrder id: 2, next_action_id: 6, order_id: 3>,
 #<NextActionsOrder id: 3, next_action_id: 6, order_id: 4>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> Order.all
=> [#<Order id: 3, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>,
 #<Order id: 4, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>]

同样,一切看起来都不错,除了现在我们有2个孤儿NextAction记录 - ID#4和#5。

有什么想法吗?非常感谢!

1 个答案:

答案 0 :(得分:1)

这是因为工厂中的next_action:next_actions_order,它会创建一个额外的next_action ......

我会使用

重写next_action工厂
after(:build) do |next_action, evaluator|
  next_action.orders << build(:order)
end

after(:build) do |next_action, evaluator|
  next_action.orders << build_list(:order, evaluator.orders_count)
end

如果您需要多个。

这样就可以立即创建整个链,所有交叉引用都应该填充! (没有双打!)