1

/object/123オブジェクトの URL を からに置き換えたい/object/f8a3b2ので、列を使用する代わりに、オブジェクトの作成時に列を手動でid生成しています。uid

uid を生成するために使用可能な uuid ライブラリを使用できますが、生成された値が常に一意であることを確認するにはどうすればよいですか?

uid 列に一意のインデックスが設定されているため、一意でない場合はエラーが返されるはずです。モデル レベルでそれをキャッチし、別の uid を作成して、再試行できますか?

4

4 に答える 4

4

これを行うにはおそらくもっと良い方法がありますが、最初に頭に浮かんだのはvalidates_uniqueness_of、あなたが提案していたように、アクティブなレコードモデルでメソッドを利用することでした.

あなたのモデルでは:

class MyUniqueModel < ActiveRecord::Base
    validates_uniqueness_of :uuid_column
end

コントローラーで

@uniqueObject = MyUniqueModel.new(modelParams)
@uniqueObject.uuid_column = generate_uuid() # whatever method you use for generating your uuid
while !uniqueObject.save # if at first it didn't save...
    uniqueObject.uuid_column = generate_uuid() # try, try again
end # should break out of the loop if the save succeeded.

モデルに他の検証がある場合、私の提案で遭遇する問題は、明らかに一意でない uuid が原因で保存が失敗したのか、それとも他の検証エラーが原因なのかを判断することです。これは、別の UUID を再生成する必要があるかどうかを判断するために、失敗した列でループ本体をフィルター処理する必要があることを意味します。

于 2012-09-24T15:23:40.980 に答える
1

uuid gemについて

uuid gemを使用している場合、一意性について心配する必要はありません。ただし、uuid は長い 128 ビットの一意の ID を生成します。したがって、より短いものが必要な場合は、使用したくない場合があります。

ニーズが単純な場合は、より簡単な方法

たとえば、ランダムでもある 8 桁の一意のコードが必要な場合は、メソッドの下のnew_unique_code私の cortex プロジェクトでそのようなシステムの実装を見ることができます。

これにより、アプリ内のリソースを表す 8 桁の英数字コードが生成されます。特定のコードを生成した後、 を実行しようとしましたが.find_by_code、それが返された場合、それがまだ使用されていないnilことがわかります。

私の特定のケースでは、8 桁の英数字コードにより、数百万の可能なコードのキースペースが得られます (その数は忘れました)。私のアプリのユースケースに基づくと、コード衝突の可能性 (使用されているコードと使用可能なコードの割合) は十分に小さいため、特定のリソースに対して新しいコードを複数回生成する必要がある可能性があります。

その結果、特定のリソースに対して新しいコードを複数回生成する必要が生じることは非常にまれであり、追加の時間はほとんどかかりません。

アプリ内の複数のアプリ サーバー/スレッドはどうですか?

私のソリューションの 1 つの制限は、アプリ サーバーが複数あり、DB サーバーが 1 つしかない場合、2 つの独立したアプリ サーバーが同じコードを生成してから、それらのいずれかが集中型 DB に新しいリソース レコードを作成する可能性があることです。これにより、コードの競合が発生する可能性があり、DB に保存された最初のレコードを除くすべてのレコードが無効とマークされる可能性があります (コード列の一意性制約のため)。この特定のアプリは、単一のアプリ サーバー インスタンス上でのみ実行されます (おそらく今後も実行される可能性があります)。これは私が認識している既知のトレードオフであるため、危険を冒すことができます。

しかし、この問題を解決したい場合は、各アプリ サーバーのランダム コードの範囲を制限して、それらが誤って重複しないようにします。たとえば、値 00000000 ~ 99999999 の間の 8 桁の数値コードとして出力されるランダム コードを生成しているとします。たとえば、このアプリを実行する 3 つのアプリ サーバーがある場合、サーバー #1 を 00000000 から 33333333 の間のコードを生成するように制限し、サーバー #2 を 33333334 から 66666666 に、サーバー #3 を 66666667 から 99999999 に制限します。このようにして、コードが重複しないことが保証され、一意のランダムなキーを 1 日中生成できます。

特定のサーバーを特定の範囲に正確に制限する方法は少し話題から外れますが、利用可能なオプションのいくつかは次のとおりです。

  1. 各アプリ サーバー内で構成設定を手動で設定します。これは手動です (したがって不安定です) が、変更されない安定した数のアプリ サーバーがある場合は、おそらくこれで問題ありません。
  2. アプリ サーバーを相互に通信させ、乱数の範囲をネゴシエートします。
  3. あきらめて、これは非常に賢い人々によって解決された複雑な問題であり、ホイールを再作成する必要はなく、UUID を使用するだけであることを認識してください。
  4. Twitter Snowflakeなど、ネットワーク サービスとして実行される一元化された一意の ID ジェネレーターの使用を検討してください。
于 2012-09-24T15:29:12.497 に答える
0

Rails Validationsを使用して一意性を検証します。

class MyModel < ActiveRecord::Base
  validates :id, uniqueness: true
end
于 2012-09-24T15:23:53.337 に答える
0

使用する必要があります

validates :uid, :uniqueness => true

uid 列の値が重複しているために DB からエラーが発生するシナリオがまだあるため、このアドバイスに警告を追加する必要があります。詳細については、Michael Hartl の RoR チュートリアルを参照してください。

重複した uid をキャッチして保存を再試行するには、次のようにします。

model = Model.create(:uid => generate_uid)
if model.errors[:uid].any?
  model.create(:uid => generate_uid)
end
于 2012-09-24T15:23:59.503 に答える