Rails: セッションの ActiveRecordStore に追加情報を入れる

クララオンライン グローバルソリューション事業部の平田です。
今回はRuby on Railsについて。

Ruby on Rails でセッション情報を ActiveRecordStore に記録する場合、そのテーブル (デフォルトでは sessions) は、セッションID (session_id)、セッションデータ (session_data)、日付 (updated_at) フィールドのみを持ちます。また、セッションはシリアライズされて (さらにBASE64エンコードされて) session_data に保存されるため、データベース上からは単なる文字列として見なされます。

この方法ではテーブルの設計にかだわることなく柔軟にセッション情報を保存することが可能ですが、データベース上からは中身のデータ構造を読み取ることができません。このため、「特定のユーザに関する一部・全てのセッションを明示的に破棄する」といった操作を行うことができません。(セキュリティの観点から、パスワードの再設定・リセット時にこのような動作が求められる場合があります。)

今回は現在のセッションに紐付いたユーザIDを保存することで、ユーザIDを元にした ActiveRecord 経由の操作を可能にする方法を紹介します。

データベースのマイグレーション

まずは、sessions テーブルにユーザのIDを格納する integer 型の user_id を追加します。

db/migrate/20140625065958_add_user_id_to_sessions.rb:

ActiveRecordStoreクラスの継承

ActiveRecordStore を利用したセッションは ActionDispatch::Session::ActiveRecordStore で取り扱っているため、これを継承した、ActionDispatch::Session::CustomizedActiveRecordStore を用意します。(クラス名を元にしたファイル名にしておくと、自動ロードされます。)

lib/action_dispatch/session/customized_active_record_store.rb:

set_session 中で session_data に含まれている Devise のユーザIDを取り出し、それを user_id フィールドに代入しています。Devise でログインしていない場合、nil (データベース上ではNULL) となります。

※ session_data の内部構造は Rails のバージョンに大きく依存するため、バージョンによってはコードの変更が必要になる可能性があります。(このコードは Rails 4.0.3で確認しました。)

※ ちなみに、Object#try は ActiveSupport によって導入されるメソッドで、NilClass では nil を返し、NilClass 以外では send (__send__) の別名になっています。これを使うと、nil? でチェックすること無くシンプルにメソッドを呼び出すことができます。

利用するセッションストアを :customized_active_record_store (CustomizedActiveRecordStore) に変更します。それ以外のオプションは任意に設定してください。

config/initializers/session_store.rb:

 セッションデータの確認

Devise の機能でログインした後、sessions テーブルの user_id に値が入っていることを確認します。

user_id にログイン中ユーザの id (123) が記録されていることを確認できました。

セッションの削除

:user_id を指定して削除します。ここでは、パフォーマンスの観点から ActiveRecord を経由しない delete_all を利用しています。(destroy_all を利用して ActiveRecord を経由させることもできますが、セッションデータが膨大になる場合は、パフォーマンスが低下する可能性があります。)

 

 

それでは。

Share on LinkedIn
LINEで送る
Pocket

平田

平田

本業はインフラエンジニアだけど、最近はプログラミングやっています。