2013-09-01 50 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