トップ «前の日記(2007-01-18) 最新 次の日記(2007-01-26)» 編集

3 日坊主日記


2007-01-20 [長年日記]

_ [Rails] 次回から自動でログインする

 <%= check_box_tag "auto" %>

何かしらチェックしたときには

 ActionController::Base.session_options[:session_expires] = Time.now + 1.month

セッションを長期間有効にする。

チェックしないときには

 ActionController::Base.session_options[:session_expires] = nil

セッションはブラウザを閉じるまで有効 (デフォルト)。

これが単純には実現できない。

 class XController
   def authenticate
     auto = params[:auto]
     # これは無効
     request.session_options[:session_expires] = auto ? Time.now + 1.month : nil

session_options はいつ反映される? session を用意するとき (初めて session にアクセスしたとき)。

session はどこで用意される?

 action_controller/cgi_process.rb:
 module ActionController
   class CgiRequest < AbstractRequest
     def session
       unless defined?(@session)
         ...
         @session = CGI::Session.new(@cgi, session_options_with_string_keys)

CGI::Session って何?

 lib/ruby/1.8/cgi/session.rb:
 class CGI
   class Session

     def initialize(request, option={})
       request.instance_eval do
         @output_hidden = {session_key => session_id} unless option['no_hidden']
         @output_cookies =  [
           Cookie::new("name" => session_key,
                       "value" => session_id,
                       "expires" => option['session_expires'],
                       "domain" => option['session_domain'],
                       "secure" => option['session_secure'],
                       "path" => if option['session_path'] then
                                   option['session_path']
                                 elsif ENV["SCRIPT_NAME"] then
                                   File::dirname(ENV["SCRIPT_NAME"])
                                 else
                                   ""
                                 end)
         ] unless option['no_cookies']
       end
 # ここでの request はたいてい CGI インスタンス

CGI::Cookie って何?

 action_controller/cgi_ext/cookie_performance_fix.rb:
 # Rails では cgi.rb のではなくこっちを使う
 CGI.module_eval { remove_const "Cookie" }

 class CGI
   class Cookie < DelegateClass(Array)

     attr_accessor("name", "value", "path", "domain", "expires")
     attr_reader("secure")

結局、session を作ってしまってから expires を書き換えるには CGI::Cookie#expires= を使えばよく、 CGI::Session から session 用の CGI::Cookie を見るには @output_cookies.first を使えばよい。

 lib/raw_session_cookie.rb:
 class CGI
   def session_cookie
     @output_cookies && @output_cookies.first
   end
 end

 module ActionController
   class CgiRequest
     def session_cookie
       @cgi.session_cookie
     end
   end
 end
 require 'raw_session_cookie'
 class XController
   def authenticate
     auto = params[:auto]
     # これは有効
     request.session_cookie.expires = auto ? Time.now + 1.month : nil

しかし、毎回 Set-Cookie ヘッダは出力されるので、filter を使わないとだめだろう (いまここ)。

(追記): RailsChat には書いたけど filter 版。

# migration
add_column :members, :auto, :boolean

# controller
def set_session_expires
  return unless @member
  request.session_cookie.expires = @member.auto ? Time.now + 1.month : nil
end
private :set_session_expires

after_filter :set_session_expires
本日のTrackBacks(全1件) []
# ぺんちゃん日記:[rails]Cookieを永続化させるには (2007-11-23 16:50)

ブラウザを閉じてもセッションを保持したい場合はCookieを永続化させるしかない。3 日坊主日記 - 次回から自動でログインするを読んですごく難しそうな印象を受けたが、なんのことはないActionController内でcookiesをexpires付きで操作すれば良い。例えば次のように。 class..