Devise3.2.2 のデフォルト設定では、Rememberable の remember_token のカラムがないのでソースを解読してみた

スポンサーリンク

Rails4 で使う認証エンジン Devise には、一定期間ユーザーのログイン状態を持続させる Rememberable モジュールがあるのですけど、デフォルトのマイグレーションではデータベースのテーブルに remember_token カラムが生成されないのがちょっと気になりまして、ソースコードを読んで解読してみました。

【お知らせ】 英単語を画像イメージで楽に暗記できる辞書サイトを作りました。英語学習中の方は、ぜひご利用ください!
画像付き英語辞書 Imagict | 英単語をイメージで暗記
【開発記録】
英単語を画像イメージで暗記できる英語辞書サービスを作って公開しました
スポンサーリンク

— 環境 —
Rails 4.0.1
Devise 3.2.2

Devise のデフォルトでのマイグレーション

Devise のデフォルトは、:database_authenticatable, :recoverable, :registerable, :rememberable, :trackable, :validatable のモジュールが有効で、以下がモデル名を user としての初期導入した時の、DBテーブル作成用のマイグレーションとなります。

Rememberable モジュールでは、remember_created_at というカラムを作成するだけとなっています。remember_token というカラムはデフォルトでは存在しません。

Rememberable モジュールのソース解読

ここからソースコード解読。まずは Rememberable モジュールの中身を読んでみる。

liv/devise/models/rememberable.rb

この remember_me! でログイン中のユーザーを記憶して、一定期間セッションを持続させます。remember_me! メソッドの1行目は、remember_token フィールドがなければ実行されないはずということで、generate_remember_token? メソッドの中身を見てみる。

予想通り、respond_to? が false を返すので、先の remember_me! の1行目は実行されず、2行目 remember_created_at がレコードに保存されることになります。ただし、これだと remember_token の役割として、ユーザーのクッキーに保存したトークンと照合させるために、DB内のどのフィールドを使うのかまだ不明です。

コメント内のヒントを読む

冒頭コメントの最後の部分に、以下の記述がありヒントになります。

クッキーに情報を保存する場合は、User.serialize_into_cookie クラスメソッドを使い、クッキー由来に基づくユーザーを探す場合、User.serialize_from_cookie メソッドを使うとある。その部分のソースを読んでみると以下。

これで、トークンとして使われる値が、record.rememberable_value という値であることが分かりました。

encrypted_password フィールドの先頭30文字が remember_token の代用

続いて、record.rememberable_value の中身を探します。

この else 節の raise のメッセージにもヒントがあります。訳しますと…
“Rememberable モジュールを使うためには、パスワードが必ず設定されているか、remember_token カラムがモデルに存在するか、独自の rememberable_value メソッドをモデルに実装する必要がある。”

ということで、remember_token フィールドがない場合は、必ずパスワードが設定されていなければなりません。これで、remember_token の代わりにパスワードが代用されるのだろうと、予測がつきました。

remember_token フィールドがない場合は、この elseif 文で rememberable_value の値(salt)が返されるはずなので、salt に値を設定する authenticatable_salt を調査します。この authenticatable_salt インスタンスメソッドは、残念ながらこのファイル(liv/devise/models/rememberable.rb)には定義されておらず、ソースを追いますと lib/devise/models/database_authenticatable.rb で定義されています。

lib/devise/models/database_authenticatable.rb

これにより、encrypted_password フィールドの値(暗号化されたパスワード)の先頭30文字が、remember_token の代用として流用されることが分かりました。この値を使って、serialize_into_cookie(record) でクッキーを保存してユーザーのログイン状態を一定期間持続させ、また serialize_from_cookie(id, remember_token) でクッキーからログイン持続中のユーザー情報を読み出すことが分かりました。remember_token フィールドが存在しなくても、Rememberable が動作することを理解できて一安心です。

Rememberable モジュールを使う場合のユニットテスト

user_spec.rb に以下のように簡単にテストを書きました。

Rememberable モジュールを使う場合で、remember_token フィールドを作成しない場合は、必ずパスワード(encrypted_password)のフィールドの値が保存される必要があります。

あけましておめでとうございます。今年もどうぞよろしくお願いいたします。

スポンサーリンク
パーフェクト Ruby on Rails は、最近読んだ Rails 本の中では一番役に立った本です。Chef や Capistrano など Rails と共によく使用される技術にも触れてあります。Ruby on Rails 4 アプリケーションプログラミングは、入門的な内容で Rails の機能全体を網羅されています。
 
スポンサーリンク
  • 2件のコメント
  • 匿名

    パスワードなしの時に remeberable が効かなくて困っていたので、非常に助かりました。
    ありがとうございますm(__)m

    • taka

      匿名さん
      お役に立てて幸いです。こちらこそ記事をお読み頂きありがとうございました。

Leave Your Message!