Rails:避免在Factory Girl中出现重复错误...我做错了吗? [英] Rails: Avoiding duplication errors in Factory Girl...am I doing it wrong?

查看:88
本文介绍了Rails:避免在Factory Girl中出现重复错误...我做错了吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个模型user,它对email字段具有唯一性约束

Suppose I have a model user, which has a uniqueness constraint on the email field

如果我一次调用Factory(:user)很好,但是如果我第二次调用它,它将失败,并显示"entry已经存在"错误.

If I call Factory(:user) once all is well, but if I call it a second time it'll fail with an "entry already exists" error.

我目前正在使用一个简单的助手在创建工厂之前调用数据库中的现有条目...并调用通过该助手创建的任何工厂.

I'm currently using a simple helper to search for an existing entry in the DB before creating the factory...and calling any factory I make through that helper.

它可以工作,但是并不完全优雅,考虑到我认为这个问题一定很普遍,我想有一个更好的解决方案.因此,工厂女孩是否有一种内置的方式来return_or_create工厂,而不是仅仅向create()收取费用?如果不是这样,大多数人如何避免他们的工厂重复录入?

It works, but it's not entirely elegant, and considering how common I assume this problem must be, I'm guessing there's a better solution. So, is there an inbuilt way in factory girl to return_or_create a factory, instead of just charging ahead with create()? If not, how do most folk avoid duplicate entries with their factories?

推荐答案

简单答案:使用factory.sequence

如果您的字段需要唯一,则可以在factory_girl中添加一个序列,以确保该字段永远不相同:

If you have a field that needs to be unique you can add a sequence in factory_girl to ensure that it is never the same:

Factory.define :user do |user|
  sequence(:email){|n| "user#{n}@factory.com" }
  user.password{ "secret" }
end

这将每次增加n以便生成唯一的电子邮件地址,例如user52@factory.com. (请参阅 https://github.com/thoughtbot/factory_girl/wiki/用法更多信息)

This will increment n each time in order to produce a unique email address such as user52@factory.com. (See https://github.com/thoughtbot/factory_girl/wiki/Usage for more info)

但是,这在Rails.env.development中并不总是很好...

随着时间的流逝,我发现这实际上并不是创建唯一电子邮件地址的最有用的方法.原因是,尽管工厂对于您的测试环境始终是唯一的,但对于您的开发环境却并非始终是唯一的,并且n会在您上下启动环境时重置自身.在:test中,这不是问题,因为已擦除数据库,但是在: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.

通常更有用:使用随机数

由于我会定期从控制台调用u = Factory :user,因此我会生成一个随机数.您不能保证避免发生冲突,但实际上几乎不会发生这种情况:

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

N.B.由于FactoryGirl [

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

可选的其他选项,可简化电子邮件测试

在进行电子邮件测试时,您通常需要验证特定用户的操作是否触发了另一位用户的电子邮件.

When you get into email testing you often want to verify that an action by a particular user triggered an email to another user.

您以Robin Hood身份登录,将电子邮件发送到Maid Marion,然后转到收件箱进行验证.您在收件箱中看到的是来自user_842@factory.com的内容.那是谁啊

You log in as Robin Hood, send an email to Maid Marion and then go to your inbox to verify it. What you see in your inbox is something from user_842@factory.com. Who the hell is that?

您需要返回数据库,以检查电子邮件是由您希望的那个人发送/接收的.再次,这有点痛苦.

You need to go back to your database to check whether the email was sent / received by whomever you expected it to be. Again this is a bit of a pain.

我想做的是使用Factory用户名和一个随机数来生成电子邮件.这使得检查来自谁的东西变得容易得多(并且也使碰撞消失的可能性很小).使用Faker宝石( http://faker.rubyforge.org/)创建我们得到的名称:

What I like to do instead is to generate the email using the name of the Factory user combined with a random number. This makes it far easier to check who things are coming from (and also makes collisions vanishingly unlikely). Using the Faker gem (http://faker.rubyforge.org/) to create the names we get:

Factory.define :user do |user|
  user.first_name { Faker::Name::first_name }
  user.last_name { Faker::Name::last_name }
  user.email {|u| "#{u.first_name}_#{u.last_name}_#{Random.rand(1000).to_s}@factory.com" }
end

最后,由于Faker有时会生成不便于电子邮件使用的名称(Mike O'Donnell),因此我们需要将可接受的字符列入白名单:.gsub(/[^a-zA-Z1-10]/, '')

finally, since Faker sometimes generates names that aren't email-friendly (Mike O'Donnell) we need to whitelist acceptable characters: .gsub(/[^a-zA-Z1-10]/, '')

Factory.define :user do |user|
  user.first_name { Faker::Name::first_name }
  user.last_name { Faker::Name::last_name }
  user.email {|u| "#{u.first_name.gsub(/[^a-zA-Z1-10]/, '')}_#{u.last_name.gsub(/[^a-zA-Z1-10]/, '')}_#{Random.rand(1000).to_s}@factory.com" }
end

这为我们提供了风趣却又独特的电子邮件,例如robin_hood_341@factory.commaid_marion_10@factory.com

This gives us personable but unique emails such as robin_hood_341@factory.com and maid_marion_10@factory.com

这篇关于Rails:避免在Factory Girl中出现重复错误...我做错了吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆