简体   繁体   中英

How to sequence correctly with factory_girl in rails development environment?

I want to integrate factory_girl in rails development environment for quickly creating records. However, every time I open rails console and do some actions, the sequence state always begins from zero, which leading to error of violating uniqueness. Such as:

FactoryGirl.define do
  factory :user do
    name 'Jim'
    email
  end

  sequence :email do |n| # every time n begins at 0
    "#{n}@exmaple.com"
  end
end

Do you have some simple solutions to solve this problem? Thank you!

You can set the initial value of n if you wish. you can achieve this by:

FactoryGirl.define do
  factory :user do
    name 'Jim'
    sequence :email, 100 do |n|
      "#{n}@exmaple.com"
    end
  end
end

or

FactoryGirl.define do
      factory :user do
        name 'Jim'
        sequence(:email, 100) { |n| "person#{n}@example.com" }
      end
end

note: n = 100 in this case for more info check out the documentation here

I think the original question was how to deal with the fact that sequences reset each time rails is restarted, not how to use sequences. The easiest thing I've done for strings that need to be unique is to append a timestamp to the end of the string.

FactoryBot.define do
  factory :user do
    name 'Jim'
    email { "jim_#{Time.now.to_f}@example.com" }
  end
end

This can also be combined with Faker, since Faker's unique call can time out or run out of options:

FactoryBot.define do
  name { Faker::Name.name + " #{Time.now.to_f}" }
  email { "#{name}@example.com" }
end

It makes for ugly strings, but you can truncate the timestamp a bit if you like, and it just works. As long as your test objects don't need to look nice, you can just slap the timestamp on the string and get on with your day.

You need the sequence statement inside of the :user factory definition:

FactoryGirl.define do
  factory :user do
    name 'Jim'
    sequence :email do |n|
      "#{n}@exmaple.com"
    end
  end
end

You can reset the sequence with FactoryBot.rewind_sequences .

I have this in my spec helper:

config.append_after(:each) do
  DatabaseCleaner.clean
  FactoryBot.rewind_sequences
end

Sadly, there isn't a way to keep the sequence as you start the environment up and down (which you probably do in development), nor are you starting with a clean db each time (as you probably do in the test environment).

From this answer talking about using factory.sequence :

However this isn't always great in Rails.env.development...

Over time I have found that this is not actually the most useful way to create unique email addresses. The reason is that while the factory is always unique for your test environment it's not always unique for your development environment and n resets itself as you start the environment up and down. In :test this isn't a problem because the database is wiped but in :development you tend to keep the same data for a while.

You then get collisions and find yourself having to manually override the email to something you know is unique which is annoying.

Often more useful: use a random number

Since I call u = Factory :user from the console on a regular basis I go instead with generating a random number. You're not guaranteed to avoid collisions but in practice it hardly ever happens:

Factory.define :user do |user|
  user.email {"user_#{Random.rand(1000).to_s}@factory.com" }
  user.password{ "secret" }
end

NB You have to use Random.rand rather than rand() because of a collision (bug?) in FactoryGirl [https://github.com/thoughtbot/factory_girl/issues/219](see here).

This frees you to create users at will from the command line regardless of whether there are already factory generated users in the database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM