2

我得到一个例外,我想了解原因。我创建了一个 git repo,所以任何人都可以测试它。

安装了 Devise 的 rails 应用程序很新鲜。

运行尝试创建相同用户的应用程序和此脚本:

1000.times do
  fork do
    `curl -d "user[email]=your@mail.com&user[password]=pwd&user[password_confirmation]=pwd" localhost:3000/users`
  end
end

我得到以下异常:

An ActiveRecord::RecordNotUnique occurred in registrations#create:

Mysql2::Error: Duplicate entry 'your@mail.com' for key 'index_users_on_email': INSERT INTO `users` (`authentication_token`, `confirmation_sent_at`, `confirmation_token`, `confirmed_at`, `created_at`, `current_sign_in_at`, `current_sign_in_ip`, `email`, `encrypted_password`, `failed_attempts`, `last_sign_in_at`, `last_sign_in_ip`, `locked_at`, `remember_created_at`, `reset_password_sent_at`, `reset_password_token`, `sign_in_count`, `unconfirmed_email`, `unlock_token`, `updated_at`) VALUES (NULL, '2013-01-24 16:48:23', 'GQwbJzsawxRsbvhp1LkR', NULL, '2013-01-24 16:48:23', NULL, NULL, 'your@mail.com', '$2a$10$koMNiiZQuhkeWhmYV8PtcOUlvi6rZHTKMs82MGWNa2M/GsUQ0cIHO', 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, '2013-01-24 16:48:23')
activerecord (3.2.11) lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'

为什么我得到这个异常而不是验证错误?如果我尝试使用已从网页“http://localhost:3000/users/sign_up”使用的电子邮件创建用户,我不会收到此异常,而是出现验证错误...

如果我在没有 fork 的情况下运行脚本(请求是顺序的),我不会收到错误。

似乎是一个竞争条件问题。

4

3 回答 3

4

在您的脚本中,您尝试使用电子邮件“your@mail.com”创建 1000 个用户。您对用户电子邮件索引有唯一性约束(正确 - 每个电子邮件地址只需要一个用户)。第二次尝试使用该电子邮件创建用户时,您将收到错误消息。

当您分叉您的请求时validates_uniqueness_of,设计提供的验证可能会成功,因为它使用相同的电子邮件查询另一条记录。但是,在实际写入记录时,可能存在另一条记录。

例如,

  1. 请求 1 检查现有电子邮件“your@mail.com” - 好的
  2. 请求 2 检查现有电子邮件“your@mail.com” - 好的
  3. 请求 1 使用电子邮件“your@mail.com”写入记录 - 好的
  4. 请求 2 使用电子邮件“your@mail.com”写入记录 - 违反唯一性。
于 2013-01-24T17:34:55.837 回答
0

好吧,就像异常说的那样,您违反了索引唯一性约束。当您运行设计生成器时,它会为您创建一个迁移(它是您在测试应用程序中的 db/migrate 中唯一拥有的一个)。在此迁移中,您有以下内容:

add_index :users, :email,                :unique => true

当您尝试使用同一封电子邮件创建一千条记录时,这就是您的脚本失败的原因。

对于初学者,我会将您的示例脚本更改为类似这样的内容,这样您每次都会收到一封独特的邮件:

1000.times do |i|
  fork do
    `curl -d "user[email]=your#{i}@mail.com&user[password]=pwd&user[password_confirmation]=pwd" localhost:3000/users`
  end
end

如果您尝试使用假用户为开发数据库播种,请查看 railscasts on database populationseed data

于 2013-01-24T17:34:16.353 回答
-2

Devise 使用电子邮件作为您用户的唯一标识符。您不能将相同的电子邮件分配给所有这些人。

或者您在脚本中尝试做的是更新用户而不是创建新用户?

于 2013-01-24T17:31:43.247 回答