2013-09-01 74 views
5

根据我的理解,工厂的to_create方法的返回值将被忽略。这意味着从工厂的'build'或'initialize_with'部分返回的对象是在测试中调用'create'时最终返回的对象。FactoryGirl to_create返回值

在我的情况下,我正在使用Repository模式的变体。我重写了工厂的'to_create'部分以包含对存储库'save'方法的调用。此方法不会修改给定对象,但会返回表示原始对象持久化形式的对象。

但是,从'build'块返回的实例是从工厂返回的,而不是在'to_create'块中创建的实例。在我的代码中,这意味着返回对象的“未被修饰的”形式,而不是具有来自保存操作的已更新属性的对象(例如'id')。

有没有办法强制'创建'的返回值是'to_create'块的结果或该块内生成的某个值?

class Foo 
    attr_accessor :id, :name 
    ... 
end 

class FooRepository 
    def self.create(name) 
    Foo.new(name) # this object is not yet persisted and has no .id 
    end 

    def self.save(foo) 
    # this method must not guarantee that the original Foo instance 
    # will always be returned 
    ... 
    updated_foo # this is a duplicate of the original object 
    end 

    ... 
end 

FactoryGirl.define do 
    factory :foo, class: FooRepository do 
    # create an example Foo 
    initialize_with { FooRepository.create(name: "Example") } 
    # save the Foo to the datastore, returning what may be a duplicate 
    to_create {|instance| FooRepository.save(instance)} 
    end 
end 

describe FooRepository do 
    it "saves the given Foo to the datastore" do 
    foo = create(:foo) 
    foo.id #=> nil 
    ... 
    end 
end 

回答

4

我没有超越“raise an issue”为你找出答案,对不起。

默认to_create回调看起来是这样的:

$ grep to_create lib/factory_girl/configuration.rb 
to_create {|instance| instance.save! } 

的主要问题是,ActiveRecord的修改自身的地方,当你调用它的save!。 FactoryGirl将忽略从to_create返回的任何新对象。

快速黑客如果要覆盖默认的创建策略:

module FactoryGirl 
    module Strategy 
    class Create 
     def association(runner) 
     runner.run 
     end 

     def result(evaluation) 
     evaluation.object.tap do |instance| 
      evaluation.notify(:after_build, instance) 
      evaluation.notify(:before_create, instance) 
      instance = evaluation.create(instance) # <-- HACK 
      evaluation.notify(:after_create, instance) 
     end 
     end 
    end 
    end 
end 

...或者这样做是为了您的to_create钩模仿Rails的就地修改:

to_create do |record| 
    new_record = YourRepositoryHere.new.create(record) 
    record.attributes = new_record.attributes # For example 
    new_record # Return the record just in case the bug is fixed 
end 

祝你好运。 :(

+0

不错!它帮助了一些不同的问题,但非常好的答案:)! – Aleks