Skip to content

Instantly share code, notes, and snippets.

@kienbt01359
Last active December 25, 2015 16:59
Show Gist options
  • Save kienbt01359/7010304 to your computer and use it in GitHub Desktop.
Save kienbt01359/7010304 to your computer and use it in GitHub Desktop.

#Tổng quan về Session

Session

Ứng dụng của bạn có 1 session cho mỗi người dùng để bạn có thể lưu một lượng data nhỏ mà sẽ tồn tại giữa nhiều request. Session chỉ khả dụng trong controller và view and có thể sử dụng một số cơ chế lưu trữ khác nhau.

  • ActionDispatch::Session::CookieStore - Lưu mọi thứ trên client.
  • ActionDispatch::Session::CacheStore - Lưu dữ liệu trong Rails cache.
  • ActionDispatch::Session::ActiveRecordStore - Lưu dữ liệu trong một cơ sở dữ liệu sử dụng Active Record.(yêu cầu gem activerecord-session_store).
  • ActionDispatch::Session::MemCacheStore - Lưu dữ liệu trong một memcached cluster (đây là một cách làm cũ; xem xét sử dụng CacheStore thay thế).
    Tất cả session chứa một cookie để lưu một ID duy nhất cho mỗi session (bạn phải sử dụng một cookie, Rails sẽ không cho phép bạn truyền session ID trong URL vì thế rất là thiếu an toàn)

    Với hầu hết các nơi chứa, ID này được sử dụng để tìm kiếm dữ liệu session trên server, ví dụ như trong bảng cơ sở dữ liệu. Có một exception, và đó là mặc định và session store khuyên dùng - CookieStore - cái mà chứa tất cả dữ liệu session trong cookie riêng của mình (ID vẫn khả dụng nếu như bạn cần nó). Điều này có ưu điểm là rất gọn nhẹ và nó không yêu cầu phải cài đặt gì trong một ứng dựng mới để sử dụng session. Dữ liệu cookie được đăng ký mật mã để chống trộm, nhưng nó không được mã hóa, nên bất kì ai truy cập vào đều có thể đọc được nội dung nhưng không thể sửa nó (Rails sẽ không chấp nhận nó nếu nó đã bị chỉnh sửa).

    CookieStore có thể lưu khoảng 4kB dữ liệu - ít hơn các loại khác - nhưng thường từng này là đủ. Lưu một lượng lớn dữ liệu trong session không được khuyến khích dù cho session đó chứa dữ liệu ứng dụng bạn sử dụng. Bạn nên đặc biết tránh việc lưu những object phức tạp (những cái gì khác mà không phải là object cơ bản của Ruby, ví dụ chung nhất trở thành model instance) trong session, kiểu như là server có thể không cho phép tái hợp chúng lại giữa các request, cái mà sẽ gây ra lỗi.

    Nếu session user của bạn không lưu trong dữ liệu quan trọng hoặc là không cần trong một khoảng thời gian dài (ví dụ nếu bạn  chỉ chỉ sử dụng flash messaging), bạn có thể xem xét sử dụng ActionDispatch::Session::CacheStore. Cái này sẽ lưu cache thực thi mà bạn đã sử dụng cho ứng dụng của bạn. Ưu điểm của điều này là bạn có thể sử dụng kết cấu hạ tầng của cache đã tồn tại để lưu session mà không yêu cầu bất kì thêm cài đặt hay quản trị nào. Nhược điểm, đương nhiên là session sẽ không bền vừng và có thể biến mất bất cứ lúc nào.

    Đọc thêm về lưu trữ session trong bài biết Security Guide

    Nếu bạn muốn một cơ chế lưu trữ session khác, bạn có thể thay đổi nó ở trong file
    config/initializers/session_store.rb
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails g active_record:session_migration")
# YourApp::Application.config.session_store :active_record_store

Rails cài một session key (tên của cookie) khi đăng ký dữ liệu session. Những thứ này đều có thể thay đổi ở trong file
config/initializers/session_store.rb

# Be sure to restart your server when you modify this file.<br/>
YourApp::Application.config.session_store :cookie_store, key: '_your_app_session'

Bạn cũng có thể truyền :domain key và định rõ tên miền cho cookie:

# Be sure to restart your server when you modify this file.
YourApp::Application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com"

Rails cài đặt(cho CookieStore) một key bí mật để đăng kí dữ liệu session. Điều này có thể được thay đổi trong file:config/initializers/secret_token.rb

# Be sure to restart your server when you modify this file.
# Your secret key for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
YourApp::Application.config.secret_key_base = '49d3f3de9ed86c74b94ad6bd0...'

Thay đổi bí mật khi sử dụng CookieStore sẽ làm vô hiệu hóa tất cả những session đang tồn tại.

Accessing the Session

Trong controller bạn có thể truy cập vào session thông qua instance method session Sessions là lazy loaded. Nếu bạn không truy cập sessions trong mã action, chúng sẽ không được load. Do đó bạn sẽ không bao giờ cần vô hiệu sessions, chỉ không truy cập chúng sẽ làm việc Session values are stored using key/value pairs like a hash: Những giá trị của session được lưu dưới dạng cặp key/value giống như hash:

class ApplicationController < ActionController::Base
  private
  # Finds the User with the ID stored in the session with the key
  # :current_user_id This is a common way to handle user login in
  # a Rails application; logging in sets the session value and
  # logging out removes it.
  def current_user
    @_current_user ||= session[:current_user_id] &&
      User.find_by_id(session[:current_user_id])
  end
end

Để lưu một cái gì đó vào session, chỉ cần gán nó vào key giống như hash:

class LoginsController < ApplicationController
  # "Create" a login, aka "log the user in"
  def create
    if user = User.authenticate(params[:username], params[:password])
      # Save the user ID in the session so it can be used in
      # subsequent requests
      session[:current_user_id] = user.id
      redirect_to root_url
    end
  end
end

Để xóa một thứ gì đó từ session, gán key đó bằng nil:

class LoginsController < ApplicationController
  # "Delete" a login, aka "log the user out"
  def destroy
    # Remove the user id from the session
    @_current_user = session[:current_user_id] = nil
    redirect_to root_url
  end
end

Để reset toàn bộ session, sử dụng reset_session

Flash

Flash là một phần đặt biệt của session cái mà bị xóa sạch với từng request. Điều này nghĩa là những giá trị đã được lưu ở đây sẽ chỉ tồn tại trong request tiếp theo, cái mà hữu ích để truyền thông báo lỗi v.v..
Nó được truy cập nhiều lần bằng 1 cách giống nhau như là session, giống như hash (đó là 1 ví dụ của FlashHash).
Hãy sử dụng hành động đăng xuất là 1 ví dụ. Controller có thể gửi một thông báo sẽ được hiển thị tới người dùng trong lần request sau đó.

class LoginsController < ApplicationController
  def destroy
    session[:current_user_id] = nil
    flash[:notice] = "You have successfully logged out."
    redirect_to root_url
  end
end

Note that it is also possible to assign a flash message as part of the redirection. You can assign :notice, :alert or the general purpose :flash: Chú ý rằng nó cũng có thể gán một flash message as là một phần của sự chuyển hưởng. Bạn có thể gián :notice, :alert hoặc là mục địch chung :flash :

redirect_to root_url, notice: "You have successfully logged out."
redirect_to root_url, alert: "You're stuck here!"
redirect_to root_url, flash: { referral_code: 1234 }

Destroy action chuyển hướng đến trang chủ, nơi mà thông báo sẽ được hiển thị. Chú ý rằng nó phụ thuộc toàn bộ quyết định của action kế tiếp, nếu có, nó sẽ thực hiện với action đặt trong flash trước đó. Nó thông thường hiển thị bất kỳ thông báo lỗi hoặc cảnh báo từ flash trong layout của ứng dụng:

<html>
  <!-- <head/> -->
  <body>
    <% flash.each do |name, msg| -%>
      <%= content_tag :div, msg, class: name %>
    <% end -%>
 
    <!-- more content -->
  </body>
</html>

Cách này, nếu một action đặt một cảnh báo hay thông báo, layout sẽ hiển thị nó một cách tự động.

Bạn có thể truyền bất cứ cái gì mà session có thể lưu, bạn không bị giới hạn các thông báo và cảnh báo:

<% if flash[:just_signed_up] %>
  <p class="welcome">Welcome to our site!</p>
<% end %>

If you want a flash value to be carried over to another request, use the keep method: Nếu bạn muốn giá trị của flash mang theo tới request khác, sử dụng hàm keep:

class MainController < ApplicationController
  # Let's say this action corresponds to root_url, but you want
  # all requests here to be redirected to UsersController#index.
  # If an action sets the flash and redirects here, the values
  # would normally be lost when another redirect happens, but you
  # can use 'keep' to make it persist for another request.
  def index
    # Will persist all flash values.
    flash.keep
 
    # You can also use a key to keep only some kind of value.
    # flash.keep(:notice)
    redirect_to users_url
  end
end

flash.now

Mặc định, thêm giá trị cho flash sẽ làm cho chúng khả dụng trong request tiếp theo, nhưng thỉnh thoảng bạn có thể muốn truy cấp những giá trị đó reques giống nhau. Ví dụ, nếu như action create thất bại trong việc lưu một resource và bạn render trang mới trực tiếp, đó không gọi lấy kết quả trong một request mới, nhưng bạn vẫn có thể muốn hiến thị một thông tin sử dụng flash. Để làm điều này, bạn có thể sử dụng flash.now như cách tương tự sử dụng flash thông thường:

class ClientsController < ApplicationController
  def create
    @client = Client.new(params[:client])
    if @client.save
      # ...
    else
      flash.now[:error] = "Could not save client"
      render action: "new"
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment