问题
I'm running into an issue where FactoryGirl appears to be creating extra records with a has_many relationship.
Given these models:
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
And these factories:
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
As you can see in the NextAction factory, I ran into an issue setting up the NextActionOrder association.
I would usually have used next_actions_orders { FactoryGirl.create(:next_actions_order) }
but with the has_many :next_actions_orders
, I was getting an undefined method 'each' for #<NextActionsOrder...
error.
next_actions_orders { FactoryGirl.create_list(:next_actions_order, 1) }
seems to work as a workaround. As shown below, this doesn't seem to be the cause of the issue, since it also exists from the create_pair
example.
The real issue is this:
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
Succinctly, the create(:next_action)
calls seem to be generating 1 additional NextAction record than is required.
I used pry to inspect this and sure enough, you can see this.
With pry inserted at the first location shown above, queries produce the following:
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>]
Here, everything looks great, except for NextAction ID #2. It's not associated anywhere, it's just an orphan record that was created for some reason.
Here's what happens with 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
With pry inserted as shown, the same queries produce:
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>]
Again, everything looks good, except now we have 2 orphan NextAction records - IDs #4 and #5.
Any ideas? Thanks so much!
回答1:
It's because of the next_action in the factory :next_actions_order, which creates an additional next_action...
I would rewrite the next_action factory using
after(:build) do |next_action, evaluator|
next_action.orders << build(:order)
end
or
after(:build) do |next_action, evaluator|
next_action.orders << build_list(:order, evaluator.orders_count)
end
if you need more than one.
This way the entire chain is created at once with all cross references filled in as they should! (and without doubles!)
来源:https://stackoverflow.com/questions/23185326/factorygirl-creating-extra-records-with-has-many-association