Найти или создать запись через factory girl association
у меня есть модель пользователя, который принадлежит группе. Группа должна иметь уникальный атрибут name. Фабрика пользователей и фабрика групп определяются как:
Factory.define :user do |f|
f.association :group, :factory => :group
# ...
end
Factory.define :group do |f|
f.name "default"
end
при создании первого пользователя также создается новая группа. Когда я пытаюсь создать второго пользователя, он терпит неудачу, потому что он хочет снова создать ту же группу.
есть ли способ сказать factory_girl метод ассоциации, чтобы сначала искать существующую запись?
Примечание: я пытался определить метод для обработки этого, но тогда я не могу использовать F.association. Я хотел бы иметь возможность использовать его в сценариях огурца, как это:
Given the following user exists:
| Email | Group |
| test@email.com | Name: mygroup |
и это может работать только в том случае, если ассоциация используется в Заводском определении.
5 ответов:
можно использовать
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
он также может быть использован с кодом
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)
, так что вы могли бы использовать.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
затем вы можете использовать их в своих определениях шагов для создания пользователей и групп отдельно и объединить их вместе по желанию. Например, можно создать одного сгруппированного пользователя и одного одинокого пользователя и присоединить его к группе сгруппированных пользователей.
в любом случае, вы должны взглянуть на огурец что позволит вам написать шаги например:
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 |
это создаст 3 пользователей с группой "mygroup". Поскольку он используется так, как это использует функциональность "find_or_create_by", первый вызов создает группу, следующие два вызова находят уже созданную группу.