Action Controller Base
Action Controller 是 Rails
網路請求的核心。它們是由一個或多個動作組成,會在收到請求時執行,然後回傳範本或重新導向到另一個動作。動作定義為控制器上的 public 方法,將會透過 Rails
路線自動提供給網路伺服器使用。
預設情況下,Rails
應用程式中的 ApplicationController 才會繼承自 ActionController::Base。所有其他控制器都會繼承 ApplicationController。這樣可以透過一個類別來設定請求偽造保護及敏感請求參數的過濾等事項。
範例控制器可能如下所示:
class PostsController < ApplicationController
def index
@posts = Post.all
end
def create
@post = Post.create params[:post]
redirect_to posts_path
end
end
動作預設會在執行動作中的程式碼後,在與控制器和動作名稱對應的 app/views
目錄中回傳一個範本。例如 PostsController 的 index
動作會在設定好 @posts
執行個體變數後,預設回傳 app/views/posts/index.html.erb
範本。
不像 index,create 動作不會回傳範本。執行完它的主要目的 (建立新的文章) 後,它會執行重新導向。這個重新導向透過回傳外部 302 Moved
HTTP 回應來運作,會將使用者帶到 index 動作。
這兩個方法代表 Action Controller 中使用兩個基本的動作原型:取得且顯示以及執行且重新導向。大部分的動作都是以下列這些主題為變化。
請求
在每個請求中,路由器會找出 controller
和 action
鍵的值。這些值決定會呼叫哪個控制器和動作。其他請求參數、工作階段 (如果有的話) 以及包含所有 HTTP 標頭的完整請求會透過存取器方法對動作公開。再執行動作。
完整的請求物件可用於透過請求存取器來取得,它主要是用於查詢 HTTP 標頭
def server_ip
location = request.env["REMOTE_ADDR"]
render plain: "This server hosted at #{location}"
end
參數
所有請求參數 (無論它們是來自於 URL 中的查詢字串,或來自於透過 POST 請求送出的表單資料) 都可以用於回傳雜湊的 params
方法中取得。例如透過 /posts?category=All&limit=5
執行的動作,將會在 params
中包含 { "category" => "All", "limit" => "5" }
。
也可以透過指定方括號中的鍵,像是這樣來建構多維的參數雜湊:
<input type="text" name="post[name]" value="david">
<input type="text" name="post[address]" value="hyacintvej">
一個包含以下輸入項目的表單中送出的請求,將會包含 { "post" => { "name" => "david", "address" => "hyacintvej" } }
。如果 address 輸入項目名稱為 post[address][street]
,params
會包含 { "post" => { "address" => { "street" => "hyacintvej" } } }
。巢狀可以無限多層。
工作階段
工作階段允許你在請求之間儲存物件。這對於尚未儲存的物件來說很有用,例如在多頁式處理中建構的 Signup 物件,或是不太會改變而且一直需要的物件,例如需要登入的系統中的 User 物件。不過,工作階段不應當做物件的快取來使用,因為物件很有可能在不知情的情況下遭到改變。要保持所有資料同步通常會有太多工作要做,而資料庫在保持資料同步方面做得很好。
透過存取雜湊,你可以透過 session
方法將物件配置在作業階段中
session[:person] = Person.authenticate(user_name, password)
你可以透過相同的雜湊再次擷取
"Hello #{session[:person]}"
移除作業階段中物件時,你可以指定單一 key 至 nil
# removes :person from session
session[:person] = nil
或可透過 reset_session
移除整個作業階段。
預設情況下,作業階段儲存在加密瀏覽器 cookie 中(請參閱 ActionDispatch::Session::CookieStore
)。因此使用者將無法讀取或編輯作業階段資料。然而,使用者可在 cookie 過期後保持一個副本,因此你應避免在基於 cookie 的作業階段中儲存敏感資料。
回應
每個動作會產生回應,包含標頭和要傳送給使用者瀏覽器的文件。實際回應物件會透過使用渲染和重新導向自動產生,不需要使用者介入。
渲染
動作控制器透過下列五種渲染方法中的其中一種將內容傳送給使用者。最通用且常見的是渲染範本。動作組合中包含動作檢視,用於啟用 ERB
範本的渲染。它已自動設定。控制器透過指定執行個體變數將物件傳遞給檢視
def show
@post = Post.find(params[:id])
end
接著,檢視便可以自動取得這些物件
Title: <%= @post.title %>
你不必仰賴自動化渲染。例如,可能產生不同範本的動作將使用手動渲染方法
def search
@results = Search.find(params[:query])
case @results.count
when 0 then render action: "no_results"
when 1 then render action: "show"
when 2..10 then render action: "show_many"
end
end
深入了解 ERB
和在 ActionView::Base
中撰寫 Builder 範本。
重新導向
重新導向用於在不同的動作之間移動。例如,在將部落格條目儲存至資料庫的 create
動作之後,我們可能會想要向使用者顯示新條目。由於我們遵循良好的 DRY 原則(別重複工作),我們將重複使用(並重新導向至)我們假設已建立的 show
動作。程式碼會如下所示
def create
@entry = Entry.new(params[:entry])
if @entry.save
# The entry was saved correctly, redirect to show
redirect_to action: 'show', id: @entry.id
else
# things didn't go so well, do something else
end
end
在此情況中,在將新條目儲存至資料庫後,使用者將重新導向至 show
方法,接著會執行該方法。請注意,這是外部的 HTTP 等級重新導向,將導致瀏覽器提出第二次要求(對 show 動作的 GET),而不是在一個要求中同時呼叫「create」和「show」的內部重新導向。
深入了解 ActionController::Redirecting
中的 redirect_to
以及你的選項。
呼叫多個重新導向或渲染
動作只能執行單一渲染或單一重新導向。再次嘗試執行其中一項將會導致 DoubleRenderError
def do_something
redirect_to action: "elsewhere"
render action: "overthere" # raises DoubleRenderError
end
如果需要根據某項條件重新導向,請務必新增「return」以停止執行。
def do_something
if monkeys.nil?
redirect_to(action: "elsewhere")
return
end
render action: "overthere" # won't be called if monkeys is nil
end
常數
模組 | = | [ AbstractController::Rendering, AbstractController::Translation, AbstractController::AssetPaths, Helpers, UrlFor, Redirecting, ActionView::Layouts, Rendering, Renderers::All, ConditionalGet, EtagWithTemplateDigest, EtagWithFlash, Caching, MimeResponds, ImplicitRender, StrongParameters, ParameterEncoding, Cookies, Flash, FormBuilder, RequestForgeryProtection, ContentSecurityPolicy, PermissionsPolicy, RateLimiting, AllowBrowser, Streaming, DataStreaming, HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, HttpAuthentication::Token::ControllerMethods, DefaultHeaders, Logging, AbstractController::Callbacks, Rescue, Instrumentation, ParamsWrapper ] |
PROTECTED_IVARS | = | AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + %i( @_params @_response @_request @_config @_url_options @_action_has_layout @_view_context_class @_view_renderer @_lookup_context @_routes @_view_runtime @_db_runtime @_helper_proxy @_marked_for_same_origin_verification @_rendered_format ) |
定義不應傳播到檢視的一些內部變數。 |
類別公開方法
without_modules(*modules) 連結
捷徑輔助器,它會傳回 `ActionController::Base` 中包含的所有模組,唯獨傳入作為引數的模組除外
class MyBaseController < ActionController::Metal
ActionController::Base.without_modules(:ParamsWrapper, :Streaming).each do |left|
include left
end
end
這樣就能更靈活地控制要排除哪些模組,而且更容易建立一個裸的控制器類別,而無需手動列出需要的模組。