グループに属するユーザーモデルがあります。グループには一意の名前属性が必要です。ユーザーファクトリとグループファクトリは次のように定義されます。
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を使用できません。このようなCucumberシナリオで使用できるようにしたいと思います。
Given the following user exists:
| Email | Group |
| [email protected] | Name: mygroup |
これは、ファクトリ定義で関連付けが使用されている場合にのみ機能します。
最終的には、ネット上で見つかった複数のメソッドを使用することになりました。そのうちの1つは、別の回答の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
_initialize_with
_メソッドで_find_or_create
_を使用できます
_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
_
For Rails 4の場合
Rails 4の正しい方法はGroup.find_or_create_by(name: name)
であるため、使用します
_initialize_with { Group.find_or_create_by(name: name) }
_
代わりに。
FactoryGirl戦略を使用してこれを達成することもできます
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
this Gist を使用できます。そして、次のことを行います
FactoryGirl.define do
factory :group do
name "name"
end
factory :user do
association :group, factory: :group, strategy: :find_or_create, name: "name"
end
end
しかし、これは私のために働いています。
通常、複数のファクトリ定義を作成します。 1つはグループを持つユーザー用で、もう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
次に、これらをステップ定義で使用して、ユーザーとグループを個別に作成し、自由に結合できます。たとえば、1人のグループ化されたユーザーと1人の孤立したユーザーを作成し、孤立したユーザーをグループ化されたユーザーチームに参加させることができます。
とにかく、 pickle gem を見てください。次のような手順を記述できます。
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....
最近、同様の問題に直面しましたが、ここで試しました。
FactoryBotのbuild
およびcreate
が引き続き正常に動作するようにするには、次を実行して、create
のロジックのみをオーバーライドする必要があります。
factory :user do
association :group, factory: :group
# ...
end
factory :group do
to_create do |instance|
instance.attributes = Group.find_or_create_by(name: instance.name).attributes
instance.reload
end
name { "default" }
end
これにより、build
が「オブジェクトの構築/初期化」のデフォルトの動作を維持し、データベースの読み取りまたは書き込みを実行しないため、常に高速になります。常に新しいレコードを作成しようとするのではなく、create
のロジックのみがオーバーライドされ、既存のレコードが存在する場合はそれをフェッチします。
記事 これを説明しました。
私はあなたの質問で説明したキュウリのシナリオを正確に使用しています:
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つの呼び出しで作成済みのグループが検索されます。