2011-08-22 5 views
50

グループに属するユーザーモデルがあります。グループには一意の名前属性が必要です。ユーザーファクトリとグループファクトリは、次のように定義されます。ファクトリ_アイルアソシエーションを介してレコードを検索または作成します。

Factory.define :user do |f| 
    f.association :group, :factory => :group 
    # ... 
end 

Factory.define :group do |f| 
    f.name "default" 
end 

最初のユーザーが作成されると、新しいグループも作成されます。 2人目のユーザーを作成しようとすると、同じグループをもう一度作成したいので失敗します。

factory_girl関連付けメソッドに、既存のレコードを最初に探す方法がありますか?

注:これを処理するメソッドを定義しようとしましたが、f.associationを使用できません。

Given the following user exists: 
    | Email   | Group   | 
    | [email protected] | Name: mygroup | 

との関連付けが工場定義で使用されている場合にのみ動作することができます:私はこのようなキュウリのシナリオで使用できるようにしたいと思います。

答えて

16

、そのうちの一つが継承されている工場:

とにかく、あなたはのような手順を書くことができますpickle gemを見てみる必要があります別の答えでduckyfuzzによって提案される。

私は次のようでした:

# in groups.rb factory 

def get_group_named(name) 
    # get existing group or create new one 
    Group.where(:name => name).first || Factory(:group, :name => name) 
end 

Factory.define :group do |f| 
    f.name "default" 
end 

# in users.rb factory 

Factory.define :user_in_whatever do |f| 
    f.group { |user| get_group_named("whatever") } 
end 
1

通常、私は複数のファクトリ定義を作成します。グループとユーザー用とgrouplessユーザーのための1:

Factory.define :user do |u| 
    u.email "email" 
    # other attributes 
end 

Factory.define :grouped_user, :parent => :user do |u| 
    u.association :group 
    # this will inherit the attributes of :user 
end 

、あなたはseperatlyユーザーおよびグループを作成し、意志でそれらを一緒に参加するためにあなたのステップの定義でこれらを使用することができます。たとえば、1人のグループ化されたユーザーと1人の孤独なユーザーを作成し、1人のユーザーをグループ化されたユーザーのチームに参加させることができます。

私はネットの周りに見られる方法の組み合わせを使用して終了
Given a user exists with email: "[email protected]" 
And a group exists with name: "default" 
And the user: "[email protected]" has joined that group 
When somethings happens.... 
0

私はあなたの質問で説明した正確キュウリのシナリオを使用しています:

Given the following user exists: 
    | Email   | Group   | 
    | [email protected] | Name: mygroup | 

あなたが好きそれを拡張することができます

Given the following user exists: 
    | Email   | Group   | 
    | [email protected] | Name: mygroup | 
    | [email protected] | Name: mygroup | 
    | [email protected] | Name: mygroup | 

このグループ「mygroup」を持つ3人のユーザーを作成します。このように使用すると、 'find_or_create_by'機能が使用され、最初の呼び出しでグループが作成され、次の2回の呼び出しですでに作成されたグループが検索されます。

89

あなたがfind_or_create方法でinitialize_withを使用することができ

FactoryGirl.define do 
    factory :group do 
    name "name" 
    initialize_with { Group.find_or_create_by_name(name)} 
    end 

    factory :user do 
    association :group 
    end 
end 

また、レールのID

FactoryGirl.define do 
    factory :group do 
    id  1 
    attr_1 "default" 
    attr_2 "default" 
    ... 
    attr_n "default" 
    initialize_with { Group.find_or_create_by_id(id)} 
    end 

    factory :user do 
    association :group 
    end 
end 

と共に使用することができる4は

レール4に正しい方法Group.find_or_create_by(name: name)あります、あなたは

を使用します210
initialize_with { Group.find_or_create_by(name: name) } 

代わりに

+6

非常にうまく動作します。ありがとうございます。 'Group.find_or_create_by(name:name)' – migu

+19

Rails 4の好ましい方法は、実際には 'Group.where(name:name).first_or_create'です。 – Laurens

+0

これはおそらく受け入れられる回答であるべきです。 Drive-by-ers ...あなたの解決策はここにあります。 – ocodo

4

また、あなたがthis gistを使用することができ、この

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

     def result(evaluation) 
     build_class(evaluation).where(get_overrides(evaluation)).first 
     end 

     private 

     def build_class(evaluation) 
     evaluation.instance_variable_get(:@attribute_assigner).instance_variable_get(:@build_class) 
     end 

     def get_overrides(evaluation = nil) 
     return @overrides unless @overrides.nil? 
     evaluation.instance_variable_get(:@attribute_assigner).instance_variable_get(:@evaluator).instance_variable_get(:@overrides).clone 
     end 
    end 

    class FindOrCreate 
     def initialize 
     @strategy = FactoryGirl.strategy_by_name(:find).new 
     end 

     delegate :association, to: :@strategy 

     def result(evaluation) 
     found_object = @strategy.result(evaluation) 

     if found_object.nil? 
      @strategy = FactoryGirl.strategy_by_name(:create).new 
      @strategy.result(evaluation) 
     else 
      found_object 
     end 
     end 
    end 
    end 

    register_strategy(:find, Strategy::Find) 
    register_strategy(:find_or_create, Strategy::FindOrCreate) 
end 

を達成するためにFactoryGirl戦略を使用することができます。 次に、以下を実行してください。

FactoryGirl.define do 
    factory :group do 
    name "name" 
    end 

    factory :user do 
    association :group, factory: :group, strategy: :find_or_create, name: "name" 
    end 
end 

これは私にとっては効果的です。

関連する問題