脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

[Ruby] sinatraでそれぞれのセッションに別々のexpiration timeを設定して、KVSみたく任意の時間で自動に消えるようにしたい

sinatraでセッションのデータにexpiration dateを持たせて、ある一定時間たったら自動で消えるっていう処理を書きたかった。

Session

すごいはまって結構がんばったけど、思い通りの実装は出来なかった。。
sinatraのsessionにも、expiration dateはある

get '/' do
  logger.info session.options
end
# => {:path=>"/", :domain=>nil, :expire_after=>nil, .............}

でも、格納する方法がわからない

logger.info session.methods.grep(/opt|exp|set/)
# => [:options, :to_set, :instance_variable_set]

ぐぐって見つけた方法を使ってみる

set :sessions, key: 'key1',
    domain: "localhost",
    path: '/',
    expire_after: 3600, #sec
    secret: 'xxx'
とか
use Rack::Session::Pool,
  path: '/',
  domain: nil,
  expire_after: 60 * 10, # Cookieの有効期限を10分に
  secret: Digest::SHA256.hexdigest(rand.to_s)
とか
  • うんともすんとも言わない。エラーさえ出ない

今使ってるsession のクラスを確認して公式ドキュメントを見てみた

logger.info session.class
# => Rack::Session::Abstract::SessionHash

Class: Rack::Session::Abstract::SessionHash — Documentation for rack/rack (master)

  • インスタンスメソッドにはないみたい
  • クラスメソッドにはset_optionメソッドがあるけど、使い方が書いてない。Gitはリンクがきれてた。
  • っていうかそもそもここで設定できても、session全体のexpire timeであって、個々のデータに設定は出来なさそう。。。

諦めるか・・・

cookie

と思った時にcookieの資料を見つけて使ってみたら一発で解決した。

get '/' do
  response.set_cookie(:foo, :value => "111", :expires => Time.now + 5)
  response.set_cookie(:bar, :value => "222", :expires => Time.now + 10000)
  logger.info request.cookies['foo']
  logger.info request.cookies['bar']
end

# 初回アクセスはまだ書き込まれてないので両方nil
I, [2015-07-22T08:24:18.724600 #5688]  INFO -- : nil
I, [2015-07-22T08:24:18.724653 #5688]  INFO -- : nil

# もう一度アクセスすると、両方書き込まれてるので値を取得できる
I, [2015-07-22T08:24:29.199283 #5688]  INFO -- : 111
I, [2015-07-22T08:24:29.199329 #5688]  INFO -- : 222

# 5秒経過してからアクセスすると:fooの方のデータは消えている
I, [2015-07-22T08:24:29.199283 #5688]  INFO -- : nil
I, [2015-07-22T08:24:29.199329 #5688]  INFO -- : 222
sessionじゃなくてcookieでいいのか?

sinatraのセッションはセッションといっても、SessionCookieでブラウザ側に保存されるので、今回の用途では問題ないと思う。たぶん