rails on ruby,ruby on rails 之Action Dispatch

Action Pack 是 Rails 應用的核心,包含三個 Ruby 模塊:ActionDispatch、ActionController 和 ActionView。 Action Dispatch 負責把請求分派給控制器,就是我我們平時所說的路由; Action Controller 處理請求,得到響應; Action View 供 Action Controller 使用,用於格式化響應。以前一直覺得Dispatch這個名詞很是高大上,但是讀過《rails 敏捷開發》之後,突然覺得這部分也不是太晦澀。

Rails 對這種接口提供了直接支持,它提供了一個路由宏方法,即 resources。 下面是我們在一個命名空間裏面定義了兩個路由:

namespace :backend do
  root 'home#index'
  resources :admins, except: %i[show]
end

我們可以利用 rake routes 指令查詢resource生成的路由:

backend_root       GET      /backend(.:format)                  backend/home#index
backend_admins     GET      /backend/admins(.:format)           backend/admins#index
new_backend_admin  GET      /backend/admins/new(.:format)       backend/admins#new
                   POST     /backend/admins(.:format)           backend/admins#create
edit_backend_admin GET      /backend/admins/:id/edit(.:format)  backend/admins#edit
backend_admin      PATCH    /backend/admins/:id(.:format)       backend/admins#update
                   PUT      /backend/admins/:id(.:format)       backend/admins#update
                   DELETE   /backend/admins/:id(.:format)       backend/admins#destroy

我們也順便來看看我們控制器是什麼樣子的:

def index
   @roles = Role.where(manager_id: current_admin.id)
end

def new
    @admin = Admin.new
end

def create
     @admin = Admin.new(admin_params)
     if @admin.save
       redirect_to backend_admins_url, notice: "Admin was successfully created(register_admin)"
     else
       render :new
     end
end

def edit
    end

def update
    if @role.update(role_params)
      redirect_to backend_admins_url, notice: "Admin was successfully updated."
    else
        render :edit
     end
end

我們首先要來看看301和302重定向狀態碼的差別。301,302 都是HTTP狀態的編碼,都代表着某個URL發生了轉移,不同之處在於:301 redirect: 301 代表永久性轉移(Permanently Moved),302 redirect: 302 代表暫時性轉移(Temporarily Moved )。但其實對用戶效果是一樣,代表某個網頁對跳轉。

我們來分析一下resource的路由:

resources :products do
get :who_bought, on: :member
end

把請求分派給控制器
簡單來說,Web 應用接收瀏覽器發來的入站請求,處理之後再發出響應。實際上,Rails 提供了兩種分派請求的方式:一種是在需要時可以使用的詳盡方式,另一種是通常使用的便利 方式。

處理請求
前面我們討論來如何把Action Dispatch 如何把入站請求分派給應用中適當的代碼,這一節討論代碼內部的事情。

控制器處理請求時,(1)會尋找與入站動作同名的公開實例方法,如果找到就會調用那個方法。如果未找到,而控制器實現了 method_missing() 方法,就會調用這個方法,並傳入動作名稱作爲第一個參數,空的參數列表作爲第二個參數。(2)如果未找到可調用的方法,控制器會尋找使用當前控制器和動作命名的模板,如果找到就會直接渲染那個模板。如果這些嘗試都失敗了,則會拋出 AbstractController::ActionNotFound 錯誤。

控制器爲動作提供環境(進而也爲動作調用的視圖提供環境)。下述方法中有很多能直接訪問 URL 或請求中:
的信息。
1. action_name
當前處理的動作的名稱。
2. cookies
和請求相關的 cookie。發送響應後,請求對象中的值存儲在瀏覽器的cookie 中。Rails 對會話的支持就基於cookie。
3. headers
一個散列,設定響應使用的 HTTP 首部。默認把 Cache-Control 設爲 no-cache。有特殊用途的應用可能需要設定 Content-Type 首部。注意,不要直接在首部中設定 cookie 值,而應該使用 cookie API。
4. params
類似散列的對象,其中包含請求參數(以及路由分派過程中生成的僞參數)。之所以說是類似散列的對象,是因爲其中的條目可以通過符號或字符串索引,例如 params[:id] 和params[‘id’] 返回相同的值。符 合習慣的做法是使用符號形式。
5. request
入站請求對象。具有下述屬性: request_method 返回請求方法,即 :delete,:get ,:post 或 :put 中的一個。

Rails 會話
首先我想明確rails會話的概念。在這之前,先來回顧一下session和cookie之間的區別:
1:session 在服務器端,cookie 在客戶端(瀏覽器)
2:session 默認被存在在服務器的一個文件裏(不是內存)
3:session 的運行依賴 session id,而 session id 是存在 cookie 中的,也就是說,如果瀏覽器禁用了cookie ,同時session也會失效(但是可以通過其它方式實現,比如在 url 中傳遞 session_id)
4:session 可以放在 文件、數據庫、或內存中都可以。
5:用戶驗證這種場合一般會用 session 因此,維持一個會話的核心就是客戶端的唯一標識,即 session id

Rails 是一種類似於散列的結構,可以實現跨請求留存。與原始的cookie不同,會話中可以存儲任何對象(只 要對象可以編組),因此特別適合保持 Web 應用的狀態信息。比如在當我們編寫購物網站的購物車模塊時,Rails每次處理請求都會保存購物車,更爲重要的是,開始處理入站,開始處理入站請求時,Rails 會恢復那個請求的購物車。有了會話,應用就好像 能記住請求一樣。

這就引出一個有趣的問題:在請求之間,這些數據具體存儲在哪裏呢?一種選擇是讓服務器把這些數據發給 客戶端,存儲在 cookie 中。這是 Rails 默認採用的方式,雖然對數據的大小有限制,而且佔用了帶寬,但是 服務器不用耗費精力管理和清理。注意,會話內容(默認)是加密的,因此用戶無法查看也無法篡改。但是我現在公司的項目中,並不是這麼做的,而是使用下面的一種方法。

另一種選擇是把數據存儲在服務器中,這種方式要做很多工作,往往得不償失。首先,Rails 要跟蹤會話。爲此,要創建一個(默認)由 32 個十六進制字符構成的鍵(因此有 16^32 種組合方式),這個鍵稱作會話 ID, 實際上是隨機的。Rails 會把這個會話 ID 存儲在瀏覽器的 cookie 中(鍵爲 _session_id),瀏覽器後續發送的請求帶有 cookie,因此 Rails 能再次獲得會話 ID。

其次,Rails 要在服務器中持久存儲會話數據,並使用會話 ID 索引。收到請求後,Rails 使用會話 ID 在存儲 器中查找數據,找到的數據是序列化後的 Ruby 對象。反序列化後,Rails 把結果存入控制器的 session 屬性 中,提供給應用代碼使用,應用可根據需要添加或修改這些數據。處理完請求後,Rails 會把會話數據再次寫入數據存儲器,然後坐等瀏覽器發送的下一次請求。關於添加或者修改session的屬性,我們正在做一個登錄跳轉的實驗,後面會將例子列出來。

會話中應該存儲些什麼呢?可以存儲任何你想存儲的數據,不過有些限制和注意事項(後面會再補充):

1.一般來說,會話中的對象必須能序列化(使用 Ruby 的 Marshal 模塊中的函數),因此不能存儲 I/O 對象。

2.別在會話數據中存儲大型對象——應該存入數據庫,然後在會話中引用。對基於cookie的會話來說這一點尤其重要,因爲 cookie 的大小限制爲 4 KB。

在這裏,我們列出一些會話存儲器,當然現在還有很多會話存儲器,但是目前只是列出兩個:

1.Rails 2.0 起使用的默認會話存儲機制。這種存儲器存儲的是編組後的對象,因此會話中能存儲任何可序列 化的數據,但是總量不能超過 4 KB。

session_store = :cookie_store
比如現在寫在config/initializers/sessions_store.rb文件中:
Rails.application.config.session_store :cookie_store, key: "#{Rails.env}_apple-service_session"

2.使用 activerecord-session_store gem 2 提供的 ActiveRecordStore 把會話數據存入應用的數據庫

session_store = :active_record_store
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章