How to avoid circular creation of related models in factory_girl?

I have an application in which a user can log in with several services, for example. Google Plus, Facebook, Twitter, etc.

To facilitate this, I have a basic model Userthat records has_many Identity.

  • Each entry Identityhas a field provider(eg "Google", "Facebook"etc.)), to indicate which provider is used to enter.
  • There is an ActiveRecord check that allows the user to have only one type of provider. Therefore, the user cannot have 2 "Google" identities.

I set up my plants as follows:

FactoryGirl.define do
  factory :user do
    sequence(:name) { |n| "Julio Jones-#{n}"}
    sequence(:email) { |n| "julio.jones-#{n}@atl.com" }

    after(:create) do |user|
      create(:identity, user: user)
    end
  end

  factory :identity do
    user

    provider "Google"
    email { user.email }
    password "password"
  end
end

The model Userhas a callback that creates a record Identity. It works great on startup

user = FactoryGirl.create(:user)

, Identity

identity = FactoryGirl.create(:identity)

the Identity factory User, , , Identity. Identity, , Identity provider User, .

, after(:create) , User :identity factory. , factory?

+4
2

, factory , . ( caller_locations, .) factory - :

FactoryGirl.define do
  factory :user do
    transient do
      create_identity true
    end

    after(:create) do |user, evaluator|
      if evaluator.create_identity
        create(:identity, user: user)
      end
    end

  end

  factory :identity do
    association :user, factory: :user, create_identity: false
  end

end
+1

, , . - nil factory.

FactoryGirl: /

:

FactoryGirl.define do
  factory :user do
    sequence(:name) { |n| "Julio Jones-#{n}"}
    sequence(:email) { |n| "julio.jones-#{n}@atl.com" }
    # we pass user: nil here because it will cause the identity factory
    # to just skip the line user { ... }.
    identity { build(:identity, user: nil) }
  end

  factory :identity do
    # we pass user: nil here because it will cause the user factory
    # to just skip the line idenitity { ... }.
    user { build(:user, identity: nil) }
    provider "Google"
    email "email@example.com"
    password "password"
  end
end 

build(:user), :

identity { build(:identity, user: nil) }

factory. , (user { build(:user, identity: nil) }), , ( ). , !

, build(:identity).


FactoryGirl: factory factory

: factory. :

factory :identity do
  ...
  email { user.email }
end

, , build(:user), nil, factory. ! , factory. , :

identity { build(:identity, user: User.new(email: email)) }

, , factory.

, :

FactoryGirl.define do
  factory :user do
    sequence(:name) { |n| "Julio Jones-#{n}"}
    sequence(:email) { |n| "julio.jones-#{n}@atl.com" }
    # we pass user: User.new here because it will...
    # a) cause the identity factory to skip the line user { ... } and
    # b) allow us to use the email attribute in the identity factory.
    identity { build(:identity, user: User.new(email: email)) }
  end

  factory :identity do
    # we pass user: nil here because it will cause the user factory
    # to just skip the line idenitity { ... }.
    user { build(:user, identity: nil) }
    provider "Google"
    email { user.email }
    password "password"
  end
end 

, !

+3

All Articles