2012-03-13 27 views
9

/wの団体この質問は、ここで提起1を拡張したものです:FactoryGirl - ユニーク制約

Using factory_girl in Rails with associations that have unique constraints. Getting duplicate errors

提供の答えは私のために完璧に取り組んできました。ここでは次のようになります。私は手動でフックで一意性制約を持つ多型の関連付けをサポートするための関連付けを構築する必要がある場合

# Creates a class variable for factories that should be only created once. 

module FactoryGirl 

    class Singleton 
    @@singletons = {} 

    def self.execute(factory_key) 
     begin 
     @@singletons[factory_key] = FactoryGirl.create(factory_key) 
     rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique 
     # already in DB so return nil 
     end 

     @@singletons[factory_key] 
    end 
    end 

end 

私のために来ている問題があります。たとえば:

class Matchup < ActiveRecord::Base 
    belongs_to :event 
    belongs_to :matchupable, :polymorphic => true 

    validates :event_id, :uniqueness => { :scope => [:matchupable_id, :matchupable_type] } 
end 

class BaseballMatchup < ActiveRecord::Base 
    has_one :matchup, :as => :matchupable 
end 

FactoryGirl.define do 
    factory :matchup do 
    event { FactoryGirl::Singleton.execute(:event) } 
    matchupable { FactoryGirl::Singleton.execute(:baseball_matchup) } 
    home_team_record '10-5' 
    away_team_record '9-6' 
    end 

    factory :baseball_matchup do 
    home_pitcher 'Joe Bloe' 
    home_pitcher_record '21-0' 
    home_pitcher_era 1.92 
    home_pitcher_arm 'R' 
    away_pitcher 'Jack John' 
    away_pitcher_record '0-21' 
    away_pitcher_era 9.92 
    away_pitcher_arm 'R' 
    after_build do |bm| 
     bm.matchup = Factory.create(:matchup, :matchupable => bm) 
    end 
    end 
end 

私の現在のシングルトンの実装はFactoryGirl::Singleton.execute(:matchup, :matchupable => bm)、のみFactoryGirl::Singleton.execute(:matchup)の呼び出しをサポートしません。

FactoryGirl::Singleton.execute(:matchup, :matchupable => bm)またはFactoryGirl::Singleton.execute(:matchup)などのコールをサポートするシングルトンファクトリを変更することをどのようにお勧めしますか?

今のところ、上記のコードはフックがfactory:baseball_matchupで実行されるたびに一意性検証エラー(「Event is already taken」)を投げます。最終的には、DBにmatchupまたはbaseball_matchupが複数存在しないように修正する必要があります。

答えて

1

::のようにすべてのこれらの変更により、コードが終了します

  1. あなたexecuteメソッドの引数としての属性を受け入れます。
  2. シングルトンファクトリの作成時に、ファクトリ名と属性の両方をオフにします。

問題を解決するには、手順1では不十分な点に注意してください。executeが属性を受け入れることを許可しても、execute(:matchup, attributes)への最初の呼び出しは、に異なる属性を渡そうとしたとしても、その結果をキャッシュし、いつでもexecute(:matchup)を返します。だから、@@singletonsハッシュのハッシュキーとして使用しているものを変更する必要もあります。

ここで私はテストの実装です:

module FactoryGirl 
    class Singleton 
    @@singletons = {} 

    def self.execute(factory_key, attributes = {}) 

     # form a unique key for this factory and set of attributes 
     key = [factory_key.to_s, '?', attributes.to_query].join 

     begin 
     @@singletons[key] = FactoryGirl.create(factory_key, attributes) 
     rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique 
     # already in DB so return nil 
     end 

     @@singletons[key] 
    end 
    end 
end 

キーは、工場名からなる文字列と属性のハッシュ("matchup?event=6&matchupable=2"のようなもの)のクエリ文字列表現です。私は異なる属性を持つ複数の異なるマッチアップを作成することができましたが、イベント/マッチ可能な組み合わせの一意性を尊重しました。

> e = FactoryGirl.create(:event) 
> bm = FactoryGirl.create(:baseball_matchup) 
> m = FactoryGirl::Singleton.execute(:matchup, :event => e, :matchupable => bm) 
> m.id 
2 
> m = FactoryGirl::Singleton.execute(:matchup, :event => e, :matchupable => bm) 
> m.id 
2 
> f = FactoryGirl.create(:event) 
> m = FactoryGirl::Singleton.execute(:matchup, :event => f, :matchupable => bm) 
> m.id 
3 

それがうまくいかない場合は教えてください。

1

Rubyのメソッドは、引数のデフォルト値を持っているので、空のデフォルトのオプションのハッシュを使用してシングルトンメソッドを定義することができます。

def self.execute(factory_key, options={}) 

今、あなたは両方の方法でそれを呼び出すことができます。

FactoryGirl::Singleton.execute(:matchup) 
    FactoryGirl::Singleton.execute(:matchup, :matchupable => bm) 

メソッド内オプションの引数ハッシュをテストして、何かが渡されたかどうかを確認してください:

if options.empty? 
    # no options specified 
else 
    # options were specified 
end 
3

Aあなたの実行関数に2番目のパラメータを定義して、FactoryGirl.createへの呼び出し中に使用する属性を送信することができます。デフォルト値は空のハッシュで、その場合はいずれも上書きしませんそれを使用しません(属性のハッシュが空の場合は、この特定の場合はチェックする必要はありません)。

この場合、begin..endブロックを定義する必要はありません。レスキュー後に実行する必要がないため、レスキューを部分の一部として定義することで簡単にすることができますメソッド定義初期化が正常だった場合の割り当ては、割り当てられた値も返すので、ハッシュに明示的にアクセスして返す必要はありません。あなたはこの仕事をするために2つのことを行う必要がある

# Creates a class variable for factories that should be only created once. 

module FactoryGirl 

    class Singleton 
    @@singletons = {} 

    def self.execute(factory_key, attrs = {}) 
     @@singletons[factory_key] = FactoryGirl.create(factory_key, attrs) 
    rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique 
     # already in DB so return nil 
    end 
    end 

end 
+0

私はFactoryGirl.createを呼び出してDBに既存のレコードがあるので(例外が発生します)、シングルトンは返されません。@@ singletons [factory_key ]救助後に。 – keruilin

関連する問題