为什么我的FactoryGirl创建方法陷入无限循环?

时间:2016-05-13 00:47:08

标签: ruby-on-rails factory-bot ruby-on-rails-5 faker

我使用的是Rails 5.0.0.rc1,ruby 2.3.0p0,factory_girl(4.7.0),factory_girl_rails(4.7.0),faker(1.6.3)。

在我的控制台,我做&得到以下内容:

[1] pry(main)> q1 = FactoryGirl.create(:question)
   (0.2ms)  BEGIN
  SQL (1.1ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "vince@harris.com"], ["created_at", 2016-05-13 00:41:03 UTC], ["updated_at", 2016-05-13 00:41:03 UTC]]
   (2.0ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.4ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "wilhelm.crona@luettgen.net"], ["created_at", 2016-05-13 00:41:04 UTC], ["updated_at", 2016-05-13 00:41:04 UTC]]
   (1.4ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.4ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "marlen@boyer.name"], ["created_at", 2016-05-13 00:41:04 UTC], ["updated_at", 2016-05-13 00:41:04 UTC]]
   (0.5ms)  COMMIT
   (0.2ms)  BEGIN
  SQL (0.3ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "brain@medhurst.io"], ["created_at", 2016-05-13 00:41:04 UTC], ["updated_at", 2016-05-13 00:41:04 UTC]]
   (0.3ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "rico.rowe@hudsonankunding.info"], ["created_at", 2016-05-13 00:41:04 UTC], ["updated_at", 2016-05-13 00:41:04 UTC]]
   (0.3ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.8ms)  INSERT INTO "users" ("email", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["email", "zakary@ritchie.io"], ["created_at", 2016-05-13 00:41:04 UTC], ["updated_at", 2016-05-13 00:41:04 UTC]]

这是我的Question工厂:

# == Schema Information
#
# Table name: questions
#
#  id                 :integer          not null, primary key
#  title              :string
#  body               :text
#  user_id            :integer
#  accepted_answer_id :integer
#  created_at         :datetime         not null
#  updated_at         :datetime         not null
#

FactoryGirl.define do
  factory :question do
    user
    association :accepted_answer, factory: :answer
    title { Faker::Lorem.sentence(3, true, 4) }
    body { Faker::Lorem.paragraphs(2, true) }
  end
end

这是我的Question模型:

# == Schema Information
#
# Table name: questions
#
#  id                 :integer          not null, primary key
#  title              :string
#  body               :text
#  user_id            :integer
#  accepted_answer_id :integer
#  created_at         :datetime         not null
#  updated_at         :datetime         not null
#

class Question < ApplicationRecord
  belongs_to :user
  belongs_to :accepted_answer, class_name: "Answer"
  has_many :answers
end

这是我的User工厂:

# == Schema Information
#
# Table name: users
#
#  id         :integer          not null, primary key
#  email      :string
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

FactoryGirl.define do
  factory :user do
    email { Faker::Internet.email }
  end
end

这是我的User模型:

# == Schema Information
#
# Table name: users
#
#  id         :integer          not null, primary key
#  email      :string
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class User < ApplicationRecord
  has_many :questions
  has_many :answers
end

修改1

这是我的Answer工厂:

# == Schema Information
#
# Table name: answers
#
#  id          :integer          not null, primary key
#  body        :text
#  user_id     :integer
#  question_id :integer
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

FactoryGirl.define do
  factory :answer do
    question
    user
    body { Faker::Lorem.paragraphs(2, true) }
  end
end

这是我的Answer模型:

# == Schema Information
#
# Table name: answers
#
#  id          :integer          not null, primary key
#  body        :text
#  user_id     :integer
#  question_id :integer
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#

class Answer < ApplicationRecord
  belongs_to :question
  belongs_to :user
end

什么可能导致无休止的用户创建循环?

1 个答案:

答案 0 :(得分:2)

您的QuestionAnswer工厂之间存在循环依赖关系。

Question构建了answer关联,answer关联构建了question关联,而这种关联反过来构建了Answer关联 - 无限制。

您在INSERT上看到User s无限追踪的原因是因为这是您当前实施问题工厂的第一件事,也是唯一的行动执行。它从来没有机会做任何其他事情,因为它陷入了无限的倒退。

与Dave的链接建议一样,最简单的解决方法可能是简单地使用after :buildafter :create来延迟构建关联,直到创建父对象为止。您也可以省略在相应的工厂定义中声明answerquestion引用,而不是在创建工厂时明确声明它们:

let(:question) { FactoryGirl.create(:question) }
let(:answer) { FactoryGirl.create(:answer, question: question) }

就个人而言,我更喜欢第二种方法,因为它的清晰度。它还可以以一些额外代码的低成本提供对测试套件的更大控制。

根据我的经验,明确了解如何在测试套件的初始化阶段定义测试数据是值得的。依赖FactoryGirl回调,约定和语法糖会导致意外行为和难以追查的混淆不一致。