地方でリモートワーク in Iwate

東京の受託開発会社でリモートワークしてます。

Rails5のhas_secure_tokenを使う場合はvalidationをかけてはいけない!

スポンサーリンク

f:id:ihatov08:20160826221248j:plain

rails5から追加されたhas_secure_token

Rails5からtokenを生成するhas_secure_tokenメソッドを使うことができます。

使用例

Schema: User(token:string, auth_token:string)
  class User < ActiveRecord::Base
    has_secure_token
    has_secure_token :auth_token
  end
  user = User.new
  user.save
  user.token # => "pX27zsMN2ViQKta1bGfLmVJE"
  user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7"
  user.regenerate_token # => true
  user.regenerate_auth_token # => true

token設定カラムにpresence valiationを設定してはいけない

上記例だとtokenとauth_tokenカラムにhas_secure_tokenメソッドを適用しています。このカラムにvalidationを適用すると、、、

validates :token, presence: true
user = User.new
user.save!
ActiveRecord::RecordInvalid: バリデーションに失敗しました: tokenを入力してください

valiationエラーが発生します。

なぜかというと、before_createでtokenカラムに値を入れているからです。presence validationを使うと、valiation時点ではnilなので、バリデーションに失敗してしまいます。

      def has_secure_token(attribute = :token)
        # Load securerandom only when has_secure_token is used.
        require "active_support/core_ext/securerandom"
        define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token }
        before_create { send("#{attribute}=", self.class.generate_unique_secure_token) unless send("#{attribute}?") }
      end

余談:tokenの長さを長くする

has_secure_tokenでは24文字のランダム文字列が生成されます。

1文字=36
2文字=1296
3文字=46656
4文字=1679616
5文字=60466176
6文字=2176782336
7文字=78364164096
8文字=2821109907456
9文字=101559956668416
10文字=3656158440062976

10桁目で3656兆

10桁で3656兆なので、24桁だとかぶることはほぼ無いと思います。 でももっと長くしたい場合は、token生成メソッドはクラスメソッドで定義されているので、クラスメソッドでgenerate_unique_secure_tokenをoverrideできます。

   class << self
    def generate_unique_secure_token
      SecureRandom.base58(30)
    end
  end