tutorial rails factorybot example bot association ruby ruby-on-rails-3 cucumber factory-bot

ruby - rails - factorybot gem



Encontrar o crear registro a través de la asociación factory_girl (5)

Estoy usando exactamente el escenario de Pepino que describiste en tu pregunta:

Given the following user exists: | Email | Group | | [email protected] | Name: mygroup |

Puedes extenderlo así:

Given the following user exists: | Email | Group | | [email protected] | Name: mygroup | | [email protected] | Name: mygroup | | [email protected] | Name: mygroup |

Esto creará 3 usuarios con el grupo "mygroup". Como se usa así utiliza la funcionalidad ''find_or_create_by'', la primera llamada crea el grupo, las dos llamadas siguientes encuentran el grupo ya creado.

Tengo un modelo de usuario que pertenece a un grupo. El grupo debe tener un atributo de nombre único. La fábrica del usuario y la fábrica del grupo se definen como:

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

Cuando se crea el primer usuario, también se crea un nuevo grupo. Cuando trato de crear un segundo usuario, falla porque quiere crear el mismo grupo nuevamente.

¿Hay alguna manera de decirle al método de asociación factory_girl que busque primero un registro existente?

Nota: Intenté definir un método para manejar esto, pero luego no puedo usar f.association. Me gustaría poder usarlo en escenarios de Pepino como este:

Given the following user exists: | Email | Group | | [email protected] | Name: mygroup |

y esto solo puede funcionar si la asociación se usa en la definición de Fábrica.


Por lo general, solo hago varias definiciones de fábrica. Uno para un usuario con un grupo y otro para un usuario sin grupo:

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

Entonces puede usarlos en las definiciones de su paso para crear usuarios y grupos por separado y unirlos a voluntad. Por ejemplo, puede crear un usuario agrupado y un usuario solitario y unir al usuario solitario al equipo de usuarios agrupados.

De todos modos, deberías echarle un vistazo a la gema de pepinillo que te permitirá escribir pasos como:

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....


Puede utilizar initialize_with con el método 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

También se puede usar con 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

Para Rails 4

La forma correcta en Rails 4 es Group.find_or_create_by(name: name) , por lo que Group.find_or_create_by(name: name)

initialize_with { Group.find_or_create_by(name: name) }

en lugar.


También puede usar una estrategia FactoryGirl para lograr esto

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

Puedes usar esta esencia . Y luego haz lo siguiente

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

Esto está funcionando para mí, sin embargo.


Terminé usando una mezcla de métodos que se encuentran en la red, uno de ellos como fábricas heredadas, como lo sugirió duckyfuzz en otra respuesta.

Lo hice siguiente:

# 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