factory_girl 연관을 통해 레코드 찾기 또는 생성
그룹에 속한 사용자 모델이 있습니다. 그룹에는 고유 한 이름 속성이 있어야합니다. 사용자 팩토리 및 그룹 팩토리는 다음과 같이 정의됩니다.
Factory.define :user do |f|
f.association :group, :factory => :group
# ...
end
Factory.define :group do |f|
f.name "default"
end
첫 번째 사용자가 생성되면 새 그룹도 생성됩니다. 두 번째 사용자를 만들려고하면 같은 그룹을 다시 만들고 싶어서 실패합니다.
factory_girl 연관 메소드에 기존 레코드를 먼저 찾도록 지시하는 방법이 있습니까?
참고 :이를 처리하는 방법을 정의하려고했지만 f.association을 사용할 수 없습니다. 다음과 같은 Cucumber 시나리오에서 사용하고 싶습니다.
Given the following user exists:
| Email | Group |
| test@email.com | Name: mygroup |
팩토리 정의에서 연관이 사용되는 경우에만 작동 할 수 있습니다.
방법 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
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
단계 정의에서이를 사용하여 사용자와 그룹을 별도로 만들고 마음대로 결합 할 수 있습니다. 예를 들어 그룹화 된 사용자 1 명과 단독 사용자 1 명을 생성하고 단독 사용자를 그룹화 된 사용자 팀에 참여시킬 수 있습니다.
어쨌든 다음과 같은 단계를 작성할 수 있는 pickle 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....
귀하의 질문에서 설명한 Cucumber 시나리오를 정확히 사용하고 있습니다.
Given the following user exists:
| Email | Group |
| test@email.com | Name: mygroup |
You can extend it like:
Given the following user exists:
| Email | Group |
| test@email.com | Name: mygroup |
| foo@email.com | Name: mygroup |
| bar@email.com | Name: mygroup |
This will create 3 users with the group "mygroup". As it used like this uses 'find_or_create_by' functionality, the first call creates the group, the next two calls finds the already created group.
I faced a similar issue lately, and here's what I tried.
To ensure FactoryBot's build
and create
still behaves as it should, we should only override the logic of create
, by doing:
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
This ensures build
maintains it's default behavior of "building/initializing the object" and does not perform any database read or write so it's always fast. Only logic of create
is overridden to fetch an existing record if exists, instead of attempting to always create a new record.
I wrote an article explaining this.
I had a similar problem and came up with this solution. It looks for a group by name and if it is found it associates the user with that group. Otherwise it creates a group by that name and then associates with it.
factory :user do
group { Group.find_by(name: 'unique_name') || FactoryBot.create(:group, name: 'unique_name') }
end
I hope this can by useful to someone :)
참고URL : https://stackoverflow.com/questions/7145256/find-or-create-record-through-factory-girl-association
'Programing' 카테고리의 다른 글
Mongoose에서 고유 한 값을 어떻게 쿼리합니까? (0) | 2020.12.04 |
---|---|
활동에서 현재 활성화 된 모든 조각에 대한 참조를 얻는 방법이 있습니까? (0) | 2020.12.04 |
자식 흐름 분기가 갈라졌습니다. (0) | 2020.12.04 |
여러 모듈에서 winston 사용 (0) | 2020.12.04 |
UICollectionView 레이아웃 문제 (0) | 2020.12.04 |