通过factory_girl关联查找或创buildlogging

我有一个用户模型属于一个组。 组必须具有唯一的名称属性。 用户工厂和组工厂定义为:

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

当创build第一个用户时,也会创build一个新组。 当我尝试创build第二个用户时,它失败了,因为它想再次创build相同的组。

有没有办法告诉factory_girl关联方法先查找一个现有的logging?

注:我确实尝试定义一个方法来处理这个,但是我不能使用f.association。 我想能够在黄瓜的情况下使用它:

 Given the following user exists: | Email | Group | | test@email.com | Name: mygroup | 

而且这只能在Factory定义中使用关联才能使用。

您可以使用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 

对于Rails 4

Rails 4中的正确方法是Group.find_or_create_by(name: name) ,所以你可以使用

 initialize_with { Group.find_or_create_by(name: name) } 

代替。

我最终使用了在网上发现的一些方法,其中一个是由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 

您也可以使用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 

你可以使用这个要点 。 然后执行以下操作

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

虽然这对我有用。

通常我只是做出多个工厂定义。 一个用于一个组和一个无组织用户的用户:

 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 

那么你可以在你的步骤定义中使用这些来分别创build用户和组,并随意组合在一起。 例如,您可以创build一个分组用户和一个单独的用户,并将单个用户join分组的用户组。

无论如何,你应该看看泡菜gem ,这将允许你写下如下步骤:

 Given a user exists with email: "hello@email.com" And a group exists with name: "default" And the user: "hello@gmail.com" has joined that group When somethings happens.... 

我正在使用您在问题中描述的黄瓜场景:

 Given the following user exists: | Email | Group | | test@email.com | Name: mygroup | 

你可以像这样扩展它:

 Given the following user exists: | Email | Group | | test@email.com | Name: mygroup | | foo@email.com | Name: mygroup | | bar@email.com | Name: mygroup | 

这将创build3个用户与组“mygroup”。 像这样使用“find_or_create_by”function,第一个调用创build组,接下来的两个调用find已经创build的组。