5

私の理解では、ファクトリの「to_create」メソッドからの戻り値は無視されます。これは、ファクトリの「build」または「initialize_with」部分から返されるオブジェクトが、テスト内で「create」を呼び出したときに最終的に返されるオブジェクトであることを意味します。

私の場合、リポジトリ パターンのバリアントを使用しています。ファクトリの「to_create」部分をオーバーライドして、リポジトリの「save」メソッドへの呼び出しを含めています。このメソッドは、指定されたオブジェクトを変更しませんが、オリジナルの永続化された形式を表すオブジェクトを返します。

ただし、「ビルド」ブロックから返されるインスタンスはファクトリから返され、「to_create」ブロックで作成されたインスタンスではありません。私のコードでは、これは、保存アクションから更新された属性 (「id」など) を持つオブジェクトではなく、オブジェクトの「永続化されていない」形式が返されることを意味します。

「create」の戻り値を「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

1 に答える 1

4

「問題を提起する」以上の答えはありません。申し訳ありません。

デフォルトの 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

幸運を祈ります。:(

于 2013-09-15T16:45:51.203 に答える