Session trong Rails

Trong công việc của bạn, đôi khi phải làm việc với session (lúc đăng nhập app, ...), tìm hiểu thêm về session cũng làm cho việc sử dụng được chủ động hơn.

Thường trong controller, khi muốn lưu 1 tài khoản đăng nhập, ta thường có câu gán session[:user_id] = current_user.id, vậy session là gì và lưu những dữ liệu này ở đâu vậy.

session đơn gỉan là 1 hash, khi binding.pry vào controller ta có thể lấy được các gía trị lưu trong session.

[1] pry(#<CompaniesController>)> session
=> {"flash"=>{"discard"=>["notice"], "flashes"=>{"notice"=>"ログインしました。"}}, "warden.user.m_employee.key"=>[[1], "$2a$10$6AqCnAGJ2YZZVqInwya16u"], "warden.user.m_employee.session"=>{"last_request_at"=>1466404289}, "_csrf_token"=>"wAGISZWlToFPxzmzgs0xQaFvdYQVW+NJLcZpUHNcu/Y="}

Thử gõ session.class ta được

[2] pry(#<CompaniesController>)> session.class
=> Rack::Session::Abstract::SessionHash

Có thể lấy options bằng cách gõ session.options

[16] pry(#<CompaniesController>)> session.options
=> {:path=>"/",
 :domain=>nil,
 :expire_after=>nil,
 :secure=>false,
 :httponly=>true,
 :defer=>false,
 :renew=>false,
 :redis_server=>"redis://localhost:6379/0/session",
 :expires_in=>10800 seconds,
 :servers=>"redis://localhost:6379/0/session"}

:expires_in=>10800 seconds, là thời gian tồn tại của session, có thể set lại bằng cách gán lại session[:expires_in] ta được

[11] pry(#<CompaniesController>)> session.options[:expires_in] = 21600.seconds
=> 20800 seconds
[12] pry(#<CompaniesController>)> session.options
=> {:path=>"/",
 :domain=>nil,
 :expire_after=>nil,
 :secure=>false,
 :httponly=>true,
 :defer=>false,
 :renew=>false,
 :redis_server=>"redis://localhost:6379/0/session",
 :expires_in=>21600 seconds,
 :servers=>"redis://localhost:6379/0/session"}

Nhưng có điểm khác biệt là session cũng được phân biệt theo id, ta thử gõ session.id

[3] pry(#<CompaniesController>)> session.id
=> "b550dbeee878df09cdaf84cb02a4c209"

Đầu tiên thử tìm hiểu về Rack::Session::Abstract::SessionHash (http://www.rubydoc.info/github/rack/rack/Rack/Session/Abstract/SessionHash)

SessionHashclass thuộc Rack::Session::Abstract, ta có thể xem class này tại https://github.com/rack/rack/blob/master/lib/rack/session/abstract/id.rb#L17

Khi ta gõ session.id thực chất là gọi method id của session

def id
  return @id if @loaded or instance_variable_defined?(:@id)
  @id = @store.send(:extract_session_id, @req)
end

Rails sẽ tạo 1 record mới khi ta gán session[:current_user_id] = current_user.id với id được gán random và được lưu ở cookies.

Khi lưu dữ liệu trong session chỉ nên lưu id của record, dung lượng cho phép đối với lưu trữ của session là 4k nên chỉ lưu những thông tin cơ bản.

Mỗi khi có request gửi lên server, session_id được trả về

curl -I http://localhost:3000/companies/1 | grep Set-Cookie
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
Set-Cookie: _session_ id = 0944e88f02029e4e11a016b282e807f4; path=/; HttpOnly

Thử gõ cookies ta được

[14] pry(#<CompaniesController>)> cookies
=> #<ActionDispatch::Cookies::CookieJar:0x007ff13eb5ace8
 @committed=false,
 @cookies={"_session_id"=>"b550dbeee878df09cdaf84cb02a4c209"},
 @delete_cookies={"request_method"=>{:path=>"/"}},
 @host="localhost",
 @key_generator=
  #<ActiveSupport::CachingKeyGenerator:0x007ff180ccd660
   @cache_keys=
    #<ThreadSafe::Cache:0x007ff180ccd638
     @backend=
      {"signed_global_ids64"=>
        "s\xE0\xF2\xD1$p\xCAK\x8D\xFA3\xA6>\x9AM\xBAJF\xCC\xDB\x13\xFD\xB2\x81\xAD\x7F\xB1b\x8E\xCE\x12\x1C\vC5\xA2\x8D\\\xFB\x9E\xDFcBv\xD8\xFE\xD7\xBF\x827D\xEE\xB6\x01\vR23*\xC3\x80\x80\xF8\xDB",
       "signed cookie64"=>
        "#-\x9D\x049\x8A\xBF^\xC1\xB7\xB4\t\xC5rg\x15h\xA8\xF5\xA5\x92>yj\x8D\x83>\xE6\x17F\x1F\fKX/\x00\ad \xD3\xA4\xC9\x1F\xAB\x0F:\r\xF3\xBA5 \x1A\xD5\xC9\x03\xDE\x87hz\xDD\xCFtq\x18"},
     @default_proc=nil>,
   @key_generator=
    #<ActiveSupport::KeyGenerator:0x007ff180ccd6b0
     @iterations=1000,
     @secret="7635f725c8bddb370d7af1080af8808088045541f6462331180dbf59856054767104f3dd801093ce875e68825388639ac2edf2e110830fbe7aefec3235244ffa">>,
 @options=
  {:signed_cookie_salt=>"signed cookie",
   :encrypted_cookie_salt=>"encrypted cookie",
   :encrypted_signed_cookie_salt=>"signed encrypted cookie",
   :secret_token=>nil,
   :secret_key_base=>"7635f725c8bddb370d7af1080af8808088045541f6462331180dbf59856054767104f3dd801093ce875e68825388639ac2edf2e110830fbe7aefec3235244ffa",
   :upgrade_legacy_signed_cookies=>false,
   :serializer=>:json,
   :digest=>nil},
 @secure=false,
 @set_cookies={}>

Ta có thể chú ý dòng @cookies={"_session_id"=>"b550dbeee878df09cdaf84cb02a4c209"}, đó chính là id được gán cho session

Link tham khảo http://www.justinweiss.com/articles/how-rails-sessions-work/


All Rights Reserved