ハッシュをクッキーに格納してみた
rubyのCGIで、クッキーに以下のようなハッシュを格納するコードを作ってみた。
hash = { 'a'=>'1', 'b'=>'2', 'c'=>'3' }
素直にクッキーに格納すると、rubyのコードはこんな感じだろうか。
require "cgi" cgi = CGI.new hash = { 'a'=>'1', 'b'=>'2', 'c'=>'3' } hash.each do |key,value| cgi.cookies[key] = CGI::Cookie.new(key, vaue) end cgi.out("cookie" => cgi.cookies){"...出力..."}
HTTPのヘッダはこんな出力になる。
Set-Cookie: a=1; path=; expires=Wed, 27 Aug 2008 08:11:36 GMT Set-Cookie: b=2; path=; expires=Wed, 27 Aug 2008 08:11:36 GMT Set-Cookie: c=3; path=; expires=Wed, 27 Aug 2008 08:11:36 GMT
キーの数が少ないうちはこれでも良いかもしれないが、クライアントが覚えておくことができるクッキーの数はドメインごとに20までなので、キーの数だけクッキーを作るのは避けたい。
そこで、ハッシュに格納されている複数のキーと値を、1つのクッキーに格納することにする。HTTPのヘッダとしては、以下のような形にしたい。
Set-Cookie: a=1&b=2&c=3; path=; expires=Wed, 27 Aug 2008 08:11:36 GMT
これを実装するRubyのコードを作ってみた。
まず、HashからCookieを作成したり、CookieからHashを復元したりするメソッドを持ったCookieHashクラスを作った。
# cookie_hash.rb class CookieHash < Hash def initialize(name, hash = {}) super() @name = name update hash end def make_cookie values = [] each do |key, value| values << "#{key}=#{value}" end return CGI::Cookie.new({'name'=>@name, 'value'=>values}) end def load_cookie(cgi) cgi.cookies[@name].each do |v| md = /(.+)=(.+)/.match v self[md[1]] = md[2] end end def name return @name end end
このCookieHashを使って、ハッシュをクッキーに格納するコードは下記のようになる。
require 'cgi' require 'cookie_hash' cgi = CGI.new hash = CookieHash.new('hash', { 'a'=>'1', 'b'=>'2', 'c'=>'3' }) cgi.out("cookie" => hash.make_cookie){"...出力..."}
上記のコードのHTTPヘッダは、以下のようになる。
Set-Cookie: hash=a%3D1&b%3D2&c%3D3; path=; expires=Wed, 27 Aug 2008 08:11:36 GMT
CGIライブラリによって'='が'%3D'に変換されてますが、1つのクッキーに格納することはできました。
そしてクッキーから値を取り出すコードの方は、下記のようになります。
require 'cgi' require 'cookie_hash' cgi = CGI.new hash = CookieHash.new('hash') hash.load_cookie(cgi) # hash の値が { 'a'=>'1', 'b'=>'2', 'c'=>'3' } になる
なおこのコードには、少し考えれば気づく事だとは思うが、以下の制約があるので、注意が必要。
- キーや値には文字列しか使えない (数値とかnilとかを入れると、取り出す時に文字列になる)
- 値に"="を含められない (取り出す時に正しく取り出せない)