1. ホーム
  2. ruby-on-rails

[解決済み] Railsでユニークなトークンを作成するための最良の方法?

2022-04-26 21:11:09

質問

私が使っているのは、こんな感じです。トークンは必ずしも推測を聞く必要はなく、何よりも短いurl識別子のようなもので、短くしたいのです。ネットで見つけたいくつかの例と、衝突したときのことを想定して、それに従いました。 と思います。 のコードでトークンが再現されますが、実際のところはわかりません。しかし、これは少し荒削りな感じがするので、私はより良い提案を見たいと思っています。

def self.create_token
    random_number = SecureRandom.hex(3)
    "1X#{random_number}"

    while Tracker.find_by_token("1X#{random_number}") != nil
      random_number = SecureRandom.hex(3)
      "1X#{random_number}"
    end
    "1X#{random_number}"
  end

私のデータベースのトークン用のカラムはユニークインデックスで、さらに validates_uniqueness_of :token しかし、これらはアプリ内のユーザーのアクションに基づいて自動的にバッチで作成されるため(ユーザーは注文を行い、トークンを購入します)、アプリがエラーを投げるようにすることは実行不可能です。

また、衝突の可能性を減らすために、最後に別の文字列を追加して、時間に基づいて生成するなどの方法も考えられますが、トークンがあまり長くなりすぎるのも困ります。

解決方法は?

-- アップデート

現在 2015年1月9日のことです。 にソリューションが実装されました。 Rails 5 ActiveRecordのセキュアトークンの実装 .

-- Rails 4 & 3 --。

今後の参考までに、安全なランダムトークンを作成し、モデルの一意性を確保します(Ruby 1.9 と ActiveRecord を使用する場合)。

class ModelName < ActiveRecord::Base

  before_create :generate_token

  protected

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64(nil, false)
      break random_token unless ModelName.exists?(token: random_token)
    end
  end

end

編集する

カイン を置き換えることを提案し、私はそれに同意しました。 begin...end..whileloop do...break unless...end というのは、以前の実装が将来削除される可能性があるからです。

編集2

Rails 4 と concerns では、これを concern に移動することをお勧めします。

# app/models/model_name.rb
class ModelName < ActiveRecord::Base
  include Tokenable
end

# app/models/concerns/tokenable.rb
module Tokenable
  extend ActiveSupport::Concern

  included do
    before_create :generate_token
  end

  protected

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64(nil, false)
      break random_token unless self.class.exists?(token: random_token)
    end
  end
end