web-dev-qa-db-ja.com

Rails "validates_uniqueness_of"大文字と小文字の区別

モデルは次のとおりです(私はSQLLite3を使用しています)。

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

たとえば、「エール」を追加した後、「エール」は追加できませんが、canは「エール」を追加します。検証で大文字と小文字を区別しないようにするにはどうすればよいですか?

編集:それを見つけました- アクティブレコード検証

86
GeekJock

validates_uniqueness_of :name, :case_sensitive => falseはトリックを行いますが、validates_uniqueness_ofnotが複数のサーバー/サーバーを持っている場合に一意性を保証することに注意してくださいプロセス(Phusion Passenger、複数のMongrelsなどの実行)またはマルチスレッドサーバー。これは、次の一連のイベントを取得する可能性があるためです(順序は重要です)。

  1. プロセスAは、「foo」という名前の新しいユーザーを作成する要求を取得します
  2. プロセスBは同じことを行います
  3. プロセスAは、その名前がまだ存在しているかどうかをDBに尋ねることにより、 'foo'の一意性を検証し、DBは名前がまだ存在しないと言います。
  4. プロセスBは同じことを行い、同じ応答を取得します
  5. プロセスAは新しいレコードのinsertステートメントを送信し、成功します
  6. そのフィールドの一意性を必要とするデータベース制約がある場合、プロセスBは新しいレコードのinsertステートメントとfailを送信しますSQLアダプタから返されるいサーバー例外。データベース制約がない場合、挿入は成功し、「foo」という名前の2つの行ができます。

validates_uniqueness_of Railsドキュメント。

から Ruby on Rails 3rd Edition

...その名前にもかかわらず、validates_uniqueness_ofは列の値が一意であることを実際に保証しません。検証の実行時に検証されるレコードの値と同じ値を持つ列がないことを確認するだけです。 2つのレコードが同時に作成され、それぞれが一意である必要がある列の値が同じであり、両方のレコードが検証に合格する可能性があります。一意性を強制する最も信頼できる方法は、データベースレベルの制約を使用することです。」

このプログラマーの経験 with validates_uniqueness_ofも参照してください。

これがよく発生する1つの方法は、新しいアカウントを作成するときにWebページから誤って二重送信されることです。ユーザーが返すのは2番目の(ugい)エラーであり、実際には成功したものの、登録が失敗したと思わせるため、これは解決が難しいものです。これを防ぐために私が見つけた最良の方法は、JavaScriptを使用して二重送信を防ぐことです。

224
Jordan Brough

大文字と小文字の区別を指定できるオプションがあります

  validates_uniqueness_of :name, :case_sensitive => false
22
vrish88

同様の質問がありますが、答えはもっと興味深いです。 https://stackoverflow.com/a/6422771

基本的に、:case_sensitive => falseは非常に非効率的なデータベースクエリを実行します。

2
Victor S