Skip to content

Instantly share code, notes, and snippets.

@khanhhd
Last active December 25, 2015 17:09
Show Gist options
  • Save khanhhd/7010829 to your computer and use it in GitHub Desktop.
Save khanhhd/7010829 to your computer and use it in GitHub Desktop.

##5. Session Trong trong ứng dụng của bạn có một session cho mỗi use mà ở đó bạn có thể lưu trữ một lượng dữ liệu nhỏ mà nó được lưu lại giữa các request. Session cũng được dùng trong controllerview và có thể sử dụng một số cơ chế lưu trữ khác:

* ActionDispatch::Session::CookieStore - lưu trữ mọi thứ trên `client`.
* ActionDispatch::Session::CacheStore - Lưu trữ dữ liệu trên Rails cache.
* ActionDispatch::Session::ActiveRecordStore - Lưu trữ dữ liệu trên db sử dụng Active Record. (require activerecord-session_store gem).
* ActionDispatch::Session::MemCacheStore - Lưu trữ dữ liệu trên `memcached cluster `(Đây  một cách thực thi kế thừa ; hãy xem các sử dụng `CacheStore`). 

Tất cả session lưu trữ sử dụng cookie để lưu trữ 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 một session ID tới URL , điều này là kém an toàn).
Hầu hết các lưu trữ, ID được sử dụng để tìm kiếm dữ liệu session trên server, ví dụ như trong bảng của cơ sở dữ liệu. có một ngoại lệ, và nó là mặc định và khuyến cáo lưu trữ session -CookieStore- lưu trữ toàn bộ dữ liệu session trong bản thân cookie (ID vẫn được sử dụng nếu bạn cần). Ưu điểm của nó là rất nhẹ và nó không cần cài đặt ở trong ứng dụng mới để sử dụng trong session. Dữ liệu cookie được mã hóa để chống trộm, như nó sẽ không được encrypted, vì vậy mọi người có thể truy cập tới nó và có thể đọc nội dung của nó nhưng không chỉnh sửa được (Rails sẽ không chấp nhận nó nếu nó đã được chỉnh sửa).
CookieStore có thể lưu trữ khoảng 4KB dữ liệu - ít hơn nhiều so với những kiểu lưu trữ khác- nhưng thường như vậy là đủ. Lưu trữ một lượng lớn dữ liệu trong session không được khuyến khích không vấn đề gì với session lưu trữ ứng dụng của bạn. Đặc biệt bạn nên tránh lưu trữ những đối tượng phức tạp ( bất cứ gì khác với các đối tượng của Ruby, một ví dụ phổ biến là thể hiện của model) trong session, cũng như server không thể tập hợp lại chúng giữa các request, kết quả sẽ là lỗi.
Nếu user session của bạn không lưu trữ giới hạn dữ liệu hoặc là không cần thời gian dài( ví dụ nếu bạn chỉ sử dụng flash để lưu trữ thông điệp), bạn có thể sử dụng ActionDispatch::Session::CacheStore. Nó sẽ lưu sessions của bạn sử dụng bộ đệm để thực thi cái mà bạn vừa thiết lập trong ứng dụng. Ưu điểm của phương pháp này là bạn có thể sử dụng kết cấu bộ nhớ đệm đã tồn tại cho việc lưu trữ session mà không cần thêm bất cứ một thiết lập nào hoặc là quyền admin. Khuyết điểm, sớm bị mất và có thể không xuất hiện bất cứ lúc nào.
Đọc thêm về lưu trữ session tại: http://guides.rubyonrails.org/security.html
Nếu bạn muộn lưu trữ session theo cơ chế 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 thiết lập một session key (tên của cookie) khi bạn đăng ký dữ liệu session. Chúng có thể thay đổi trong file config/initializers/session_store.rb

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

Bạn cũng có thể truyền qua một khóa :domain và chỉ ra tên miền của 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 thiết lập (cho CookieStore) một key bí mật được sử dụng cho việc truy cập dữ liệu session. Nó có thể 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 khóa bí mật này khi bạn sử dụng CookieStore nó sẽ không hợp lễ trong tất cả các session đã tồn tại. ###5.1 Truy cập vào Session Trong controller bạn có thể truy vào session thông qua instance method.

Những `Session` là `lazily loaded`. Nếu bạn không truy cập vào `session` trong `action's code`, nó sẽ không được load. Do đó bạn không cần phải hủy `session`, Không chỉ là truy cập chúng sẽ làm việc.

Giá trị của session được lưu trữ sử 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ì đó trong 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 cái gì đó trong session, chỉ việc gán key của nó thành 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 lại toàn bộ session sử dụng reset_session ##5.2 Flash Flash là một phần đặc biệt của session mà nó sẽ được xóa sau mỗi request. Điều đó có nghĩa là giá trị đó sẽ chỉ được dùng ở request tiếp theo, nó rất hữu ích để truyền các message lỗi...
Nó truy cập khá giống với cách truy cập của sess ion, như một hash (nó là một FlashHash instance).
Ví dụ sử dụng cho việc đăng xuất chẳng hạn. controller có thể gửi

message mà nó sẽ được hiển thị cho người dùng ở request tiếp theo:

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

Chú ý rằng nó cũng có gán flash message trong một phần của việc chuyển hướng. Bạn có thể gán :notice, :alert, hoặc là theo mục đích

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 }

Action destroy đi tới root_url của ứng dụng, wor đó message sẽ được hiển thị. Chú ý rằng nó phụ thuộc hoàn toàn vào action tiếp theo, nếu bất cứ thứ gì, nó sẽ làm việc với action trước put vào flash. Nó rất thuận tiện để hiển thị lỗi alert hoặc notice từ flash trong application's layout:

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

Bằng cách này nếu một action gán một notice hoặc một alert message, layout sẽ tự động hiển thị nó.
Bạn có thể truyền bất cứ gì mà session có thể lưu trữ; không chỉ có notice hoặc alert mà bạn có thể dùng cái mà mình muốn

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

Nếu như bạn muốn giá trị của flash được chuyển qua một request khác bạn phải sử dụng phương thức 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

##5.2.1 flash.now Mặc định, thêm giá trị vào flash sẽ làm chúng có thể sử dụng trong request tiếp theo, nếu đôi khi bạn muốn truy cập vào những giá chị của chúng trong cùng một request. Ví dụ, nếu action createfails khi bạn lưu một resoure và bạn rendertrực tiếp một template mới, nó sẽ không đi tới kết quả của một request mới, nó có thể vẫn hiện thị message sử dụng flash. Để làm được điều này bạn có thể sử dụng flash.now cũng giống như bạn sử dụng flash:

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