has_many同时尊重factory_girl中的构建策略

情况

# Models class User < ActiveRecord::Base has_many :items end class Items  :user) do |u| u.items {|items| [items.association(:item), items.association(:item)]} end Factory.define(:item) do |i| i.color "red" end Factory.define(:item_with_user, :parent => :user) do |i| i.association(:user) end 

问题

如果你运行@user = Factory(:user_with_items)那么@user.items包含这两个项目。 问题是这些项目与数据库中的用户没有关联。 如果你重新加载关联@user.items(true)那么你会得到一个空数组。 我知道你可以手动构建它们或者自己创建辅助方法来构建对象图,但我想避免这种情况。

所以,我的问题是如何在尊重构建策略的同时在factory_girl中建立一个has_many关系?

我用inheritance和所有这些正确地写了它。 我的提交在这里和这里合并。

它现在在FactoryGirl 1.2.3中,哇!

我最终修补了工厂女孩以允许after_buildafter_create回调。

履行

 Factory.class_eval do def run (proxy_class, overrides) #:nodoc: proxy = proxy_class.new(build_class) proxy.callbacks = @callbacks overrides = symbolize_keys(overrides) overrides.each {|attr, val| proxy.set(attr, val) } passed_keys = overrides.keys.collect {|k| Factory.aliases_for(k) }.flatten @attributes.each do |attribute| unless passed_keys.include?(attribute.name) attribute.add_to(proxy) end end proxy.result end def after_create(&block) @callbacks ||= {} @callbacks[:after_create] = block end def after_build(&block) @callbacks ||= {} @callbacks[:after_build] = block end end Factory::Proxy.class_eval do attr_accessor :callbacks def run_callback(name) callbacks && callbacks[name] && callbacks[name].call(@instance) end end Factory::Proxy::Build.class_eval do def result run_callback(:after_build) @instance end end Factory::Proxy::Create.class_eval do def result run_callback(:after_build) @instance.save! run_callback(:after_create) @instance end end 

这可能是一个邪恶的双胞胎或只是你需要的扩展。

示例用法

 # Models class User < ActiveRecord::Base has_many :items end class Items < ActiveRecord::Base belongs_to :user validates_presence_of :user_id end # Factories Factory.define(:user) do |u| u.name "foo" end Factory.define(:user_with_items, :parent => :user) do |u| u.after_build do |o| o.items = [Factory.build(:item, :user => o), Factory.build(:item, :user => o)] end end Factory.define(:item) do |i| i.color "red" end Factory.define(:item_with_user, :parent => :user) do |i| i.association(:user) end # Run user = Factory(:user_with_items) user.items(true) # Shows the two saved items 

希望这可以帮助将来的某个人。 我可能会尝试将这个提交给thinkbot上的那些人,但是他们的bug跟踪器上已经有一些关于这个主题的陈旧故障了。

我通常喜欢分离构建和创建,所以我仍然可以构建对象而无需访问数据库。

 Factory.define(:user_with_items, :parent => :user) do |u| u.after_build do |u| u.items = (1..2).map {Factory.build(:item, :user => u)} end u.after_create do |u| u.items.each {|i| i.save!} end end