【问题标题】:FactoryGirl association Parent can't be blankFactoryGirl 关联 Parent 不能为空
【发布时间】:2013-08-20 00:28:49
【问题描述】:

我正在尝试使用 FactoryGirl 创建一个关联为 Parent has_many Entries 的测试数据库。此时,它正在抛出 Parent 不能为空的 ActiveRecord 验证错误。我在这个方面遇到了困难,并且尝试了很多很多方法来创建这个关联的测试数据库。我想我已经很接近了,但我可能还没有接近,并且可能有基本错误,因此非常感谢任何和所有建议。

我的猜测是哈希 { parent_id: :id } 没有被传递到入口工厂。那将无法通过验证。但是,我不知道事实是否如此,即使是这样,我也不知道如何解决它。在此先感谢您的帮助...

错误是:

ActiveRecord::RecordInvalid: 验证失败:父级不能为空

RSpec 调用是:

before(:all) do
  rand(11..25).times { FactoryGirl.create(:parent) }
  visit "/parents?direction=asc&sort=parent_blog"  
end
after(:all)  do
  Parent.delete_all
end

父模型是:

class Parent < ActiveRecord::Base
  has_many :entries, dependent: :destroy
  accepts_nested_attributes_for :entries, :allow_destroy => :true
  validates :parent_blog, presence: true,
              uniqueness: true
end

Entry 模型是:

class Entry < ActiveRecord::Base
  belongs_to :parent
  validates :entry_blog,     presence:true,
            uniqueness: true
  validates :parent_id,       presence: true
end

父工厂是:

FactoryGirl.define do
  factory :parent do
    sequence(:parent_blog) { |n| "http://www.parent%.3d.com/ss" % n }
    entries { rand(5..15).times { FactoryGirl.create(:entry,  parent_id: :id) } }
  end
end

入口工厂是:

FactoryGirl.define do
  factory :entry do
    sequence(:entry_blog)      { |n| "http://www.parent%.3d.com/ss/entry%.3d" % [n, n] }
    parent_id                   { :parent_id }
  end
end

【问题讨论】:

    标签: activerecord rspec factory-bot


    【解决方案1】:

    对您的工厂定义进行以下修改应该可以工作。稍后我会回来提供一些解释。

    FactoryGirl.define do
    
      factory :parent do
        sequence(:parent_blog) { |n| "http://www.parent%.3d.com/ss" % n }
        after(:create) {|parent| rand(5..15).times {FactoryGirl.create(:entry, parent: parent)}}
      end
    
      factory :entry do
        sequence(:entry_blog)   { |n| "http://www.parent%.3d.com/ss/entry%.3d" % [n, n] }
        parent
      end
    
    end
    

    这两个变化,在:parent 工厂中引入after 和使用parent 代替parent_id,都是RSpec 支持关联的示例,如https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations 中所述。

    至于为什么你的代码不起作用,我现在只能提供部分答案。您不能将 entries 作为初始父创建的一部分包含的原因是,在创建父记录之前您没有父 ID,但是由于 Entry 验证,您需要父 ID 来创建条目parent_id 的存在。换句话说,parent_id 在您的父工厂中评估 entries 块时尚未设置。

    我不确定的是为什么您不能在入口工厂中将parent 替换为parent_id,并在父工厂的FactoryGirl.create 调用中相应地将parent: parent 替换为parent_id: parent.id。我在提交上述内容之前尝试了该变体,但失败了:

      1) test
         Failure/Error: rand(11..25).times { FactoryGirl.create(:parent) }
         ArgumentError:
           Trait not registered: parent_id
         # ./spec/factories.rb:4:in `block (4 levels) in <top (required)>'
         # ./spec/factories.rb:4:in `times'
         # ./spec/factories.rb:4:in `block (3 levels) in <top (required)>'
         # ./tmp/factory_spec.rb:5:in `block (3 levels) in <top (required)>'
         # ./tmp/factory_spec.rb:5:in `times'
         # ./tmp/factory_spec.rb:5:in `block (2 levels) in <top (required)>'
    

    如果/当我弄清楚时,我会再次更新这个答案。

    【讨论】:

    • 我当然会喜欢听这个解释,因为我不明白。 after(:create) 很有意义,事实上,我曾在我的一次迭代中尝试过。但是,我不明白 factory :entry 中对“父级”的引用。我假设它提供/支持该关联。无论如何,您的建议非常有效。谢谢。
    • 抱歉这么久才回复您。查看更新的答案。
    • 这一切都对我有用,无需进一步跟进。谢谢。
    【解决方案2】:

    我从工厂机器人 4.11 升级到 6.2 时遇到了这个问题。我怀疑这是因为factory bot 5 changeChanged: use_parent_strategy now defaults to true, so by default the build strategy will build, rather than create associations

    这是我的父工厂和子工厂的样子:

      factory :parent do
        sequence(:name) { |n| "Parent #{n}" }
      end
    
      factory :child do
        sequence(:name) { |n| "Child #{n}" }
        parent
      end
    

    我不得不改变我在规范文件中定义变量的方式。 而不是:

    let(:parent){ create(:parent) }
    let(:child) { build(:department) }
    

    用过这个:

    let(:parent){ create(:parent) }
    let(:child) { build(:department, parent: parent) }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多