2013-03-17 33 views
11

Ruby on Railsアプリケーションでは、ユーザーがファイルをアップロードできるようにしていて、これらのファイルに短くランダムな英数字の名前を付けたいと考えています。 (例えば、 'g7jf8'または '3bp76')。これを行う最善の方法は何ですか?Rubyでランダムでユニークな文字列を生成する方法はありますか?

私は、元のファイル名とタイムスタンプからハッシュ/暗号化された文字列を生成することを考えています。次に、それが存在しないことを二重チェックするためにデータベースを照会します。そうであれば、別のものを生成し、繰り返す。

このアプローチで見られる問題は、重複した文字列の高い可能性がある場合、データベースベースの負荷がかなり増加する可能性があるということです。

+1

同じ名前を同時に追加しようとする2つの要求の可能性のある競合条件があります。データベースはその列に対してユニークな制約を持つ必要があり、 'ActiveRecord :: RecordNotUnique'をキャッチする準備が必要です。 – mpartel

+0

check http://stackoverflow.com/questions/5966910/generate-unique-rand-string-with-letters-and-numbers-in-lower-case – sameera207

+0

「ランダム」名はセキュリティ上の目的を持っていますか?そうでない場合は、さらに多くのオプションがあります。 –

答えて

9

:)

def generate_token(column, length = 64) 
    begin 
    self[column] = SecureRandom.urlsafe_base64 length 
    end while Model.exists?(column => self[column]) 
end 

、それはまた、タイムスタンプを持っているので、これは常に、新しいuniqの40サイズの英数字の文字列を生成しますお使いのモデル名で

5

RubyのSecureRandom.hex関数を、生成したい文字の任意の数で使用します。

+3

この質問のお気に入りは、代わりに 'SecureRandom.urlsafe_base64'かもしれません。 –

0

新しいファイルが追加されるたびに一意のIDをインクリメントし、そのIDをOpenSSL::Cipherのどこかに保存して暗号化された文字列に変換することができます。

0

最終的に16進または数値ダイジェストを生成する場合は、コードを短くすることができます。基本62:

# This is a lightweight base62 encoding for Ruby integers. 
B62CHARS = ('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a 

def base62_string nbr 
    b62 = '' 
    while nbr > 0 
    b62 << B62CHARS[nbr % 62] 
    nbr /= 62 
    end 
    b62.reverse 
end 

あなたが使用される文字セット(例えば、ファイル名に大文字の文字を持っていない)は、このコードは容易に適合させることができるを制限することが重要である場合は、給餌の方法を見つけることができます提供適切な乱数で

ファイル名が準安全であると想定されている場合は、ストレージに実際の名前よりも多くの名前がある可能性があることを確認する必要があります。

+0

これはOPが要求したものではありません。同じ 'nbr'を指定すると、毎回同じ文字列が返されます。大規模な文字列を返すには、大量の数値を渡す必要があります。例: '> base62_string 99999999999999999999 =>" 1V973MbJYWoT "' –

+0

@ Chrisbloom7:合意しました。これは数字を入力する必要がありますが、取得方法は説明していません(ただし、これは必須です)。 Rubyでは適切なサイズの乱数を生成することは簡単ですが、 'SecureRandom.random_number(2 ** 128)'です。このアプローチは、シーケンス、ハッシュなどでも機能します。短い文字列を作成するには巨大な入力が必要であるという事実は、実際にはOPにとって望ましいです。短い文字列を要求します。 –

8
SecureRandom.uuid 

グローバルに一意の文字列を提供します。 http://en.m.wikipedia.org/wiki/Universally_unique_identifier

SecureRandom.hex 32 

は、ランダムな文字列を与えるだろうが、それは、アルゴリズムは、独自性のために最適化されていないのです。もちろん、真のランダム性を仮定して、32桁の衝突の可能性は、基本的に理論的です。あなたは100年間、毎秒10億を作り、衝突の確率はわずか50%です。

-1

実際に固有のファイル名が必要なようですね。複雑なソリューションを忘れずに、単にTime#nsecを使用してみませんか?

私はこれを使用
t = Time.now  #=> 2007-11-17 15:18:03 +0900 
"%10.9f" % t.to_f #=> "1195280283.536151409" 
+0

アプリケーションが大規模でビジーで、最終的に2人が同時にファイルを処理し、衝突を起こします。 –

+0

Concat _nanosecs_サーバーの名前が完全であること。 – mudasobwa

+1

その時点で、SecureRandom.uuidはもっと簡単な解決策です。 –

0

Modelを交換してください。

ループが

random_token = Digest::SHA1.hexdigest([Time.now, rand(111..999)].join) 

    break random_token unless Model.exists?(column_name: random_token) 

エンド

注操作を行います。あなたのモデルのいずれかの既存の列で、あなたのMODEL_NAMEおよびCOLUMN_NAMEでモデルを交換してください。

関連する問題