通过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的组。