2

例外が発生し、その理由を理解したいと思います。誰でもテストできるように、gitリポジトリを作成しました。

Railsアプリは、Deviseがインストールされた新しいものです。

同じユーザーを作成しようとするアプリとこのスクリプトを実行する:

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'

検証エラーではなく、この例外が発生するのはなぜですか?Webページ「http:// localhost:3000 / users / sign_up」からすでに使用されている電子メールでユーザーを作成しようとすると、この例外は発生しませんが、検証エラーが発生します...

フォークなしでスクリプトを実行した場合(リクエストはシーケンシャルです)、エラーは発生しません。

競合状態の問題のようです。

4

3 に答える 3

4

スクリプトでは、すべてメール「your@mail.com」で1000人のユーザーを作成しようとします。ユーザーの電子メールインデックスに一意性の制約があります(正しくは、電子メールアドレスごとに1人のユーザーのみが必要です)。2回目にその電子メールでユーザーを作成しようとすると、エラーが発生します。

リクエストをフォークしているときに、devisevalidates_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

例外が言うように、インデックスの一意性の制約に違反しています。Deviseジェネレーターを実行すると、移行が作成されます(テストアプリのdb / migrateにあるのはこれだけです)。この移行では、次のようになります。

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

これが、同じ電子メールで1000レコードを作成しようとしたときにスクリプトが失敗する原因です。

手始めに、サンプルスクリプトを次のようなものに変更して、毎回一意のメールを受け取るようにします。

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

開発データベースに偽のユーザーをシードすることを試みている場合は、データベースの母集団シードデータに関するrailscastを確認してください。

于 2013-01-24T17:34:16.353 に答える
-2

Deviseは、電子メールをユーザーの一意の識別子として使用します。それらすべてに同じメールアドレスを割り当てることはできません。

または、スクリプトで実行しようとしたのは、新しいユーザーを作成するのではなく、ユーザーを更新することでしょうか。

于 2013-01-24T17:31:43.247 に答える