iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
自我挑戰組

富士大顆系列 第 18

vol. 18 Rails 的 render 和 redirect_to 有什麼差別?

  • 分享至 

  • xImage
  •  

你好,我是富士大顆 Aiko
今天來談談比較單純的題目: renderredirect_to


以下是 renderredirect_to 不同之處:

差異 render redirect_to
HTTP request 在同一個週期內 發出一個新的 request
URL 變化 不變 會改變
傳遞變數 可以將 Controller 中的實例變數傳遞到 View 需要使用 session 或 URL 參數
效能 較好,因為沒有額外的 HTTP 請求 較差,因為需要一個額外的 HTTP request
主要用途 主要用於渲染特定的 View 將 user 導到不同的route 或外部 URL
狀態碼 通常是 200 OK 通常是 302 Found

render

常見的 render 用法:

def show
  @article = Article.find(params[:id])
  render :show
end

render :show 會將 @article 實例變數渲染到對應的 show View 檔案。
(檔案路徑會是 app/views/[控制器名稱的複數形式]/show.html.erb。在這個例子中,就是 app/views/articles/show.html.erb。)

render 尤其在表單送出失敗時很有用,因為可以直接將錯誤信息渲染 View 中。保留 user 所填的資料,而不換頁:

def show
  @article = Article.find(params[:id])
  respond_to do |format|
    format.html { render :show }
    format.json { render json: @article }
  end
end

除此之外,render 還有一些其他常見用法:

  1. 渲染特定樣式(Template):例如,render "articles/show" 會渲染在 articles 目錄下名為 show 的樣式。
def show
  @article = Article.find(params[:id])
  render "articles/show"
end

會尋找 app/views/articles/show.html.erb 並渲染它

  1. 渲染不同控制器(Controller)的 View
def show
  @book = Book.find(params[:id])
  render 'books/show'
end

這會渲染在 app/views/books/show.html.erb 的樣式,即使這個 show 方法不是 BooksController 的 action。

  1. 渲染純文字(Plain Text)
def show
  render plain: "OK"
end

render plain: "OK" 會直接回傳一個純文字 "OK"。

  1. 渲染 JSON
def show
  @article = Article.find(params[:id])
  render json: @article
end

render json: @article 會將 @article 物件轉為 JSON 格式並回傳。

  1. 指定狀態碼
def show
  render status: 404
end

render status: 404 會設定 HTTP 狀態碼為 404。

  1. Inline 樣式
def index
  @products = Product.all
  render inline: "<% @products.each do |p| %> <p><%= p.name %></p> <% end %>"
end

類似 inline style 的概念,使用嵌入在控制器中的 ERB 樣式來渲染。

  1. 條件性渲染(Conditional Rendering)
    透過 respond_to 來根據請求類型(如 HTML、XML、JSON 等)渲染不同的內容。
def show
  @article = Article.find(params[:id])
  respond_to do |format|
    format.html { render :show }
    format.json { render json: @article }
  end
end

HTML 請求: 當客戶端請求 HTML 格式(通常是瀏覽器)時,會執行 format.html { render :show },這會渲染 show.html.erb 這個 View。

JSON 請求: 如果客戶端發出 JSON 請求(可能是 API 請求或 Ajax 請求),會執行 format.json { render json: @article },這會將 @article 物件轉換為 JSON 格式並回傳。

所以可以在同一個控制器的 Action 中處理多種不同格式的請求,這對於建立支持多種客戶端(如網站、手機應用程式等)的應用程式非常有用。

例如,你的網站前端可能會發出 HTML 請求以讀取網頁,而手機應用程式則可能會發出 JSON 請求。使用 respond_to,就能在同一個 Controller 動作中同時處理這兩種請求。


redirect_to

使用 redirect_to 常常是因為某些操作需要一個新的請求週期來完成,例如新增、更新或刪除資料後導向到不同的頁面。
常見的 redirect_to 用法

def create
  @article = Article.new(article_params)
  if @article.save
    redirect_to @article
  else
    render :new
  end
end

如何用 redierct_to 傳遞變數?

1. 透過 URL 參數

最簡單的方法是將變數新增到 URL 參數中。這種方法適用於簡單和不敏感的資料。

#ArticlesController
def create
  @article = Article.new(article_params)
  if @article.save
    redirect_to article_path(@article, foo: 'bar', baz: 'qux')
  else
    render :new
  end
end

這樣會導向一個 URL 類似於 /articles/1?foo=bar&baz=qux,然後你可以在目標控制器(Target Controller)中使用 params[:foo]params[:baz] 來得到這些值。目標控制器指的是 redirect_to 所指向的控制器,在這個例子就會是 Article#show ,因為 create 完之後根據 RESTful 會是到該文章的 show,這個 id 參數是從 @article 物件中取得的。這裡的 @ariticle = @article.to_param(通常就是回傳 id) = @article.id。

2. 使用 Session

對於更為複雜或敏感的資料,你可以使用 session。Session 是一個用於儲存 user 特定資料的 Ruby Hash。可以在其中存放變數,然後在 redirect_to 之後的請求中讀取它。

def create
  @article = Article.new(article_params)
  if @article.save
    session[:article_id] = @article.id
    redirect_to @article
  else
    render :new
  end
end

def show
  @article = Article.find(session[:article_id])
  # 其他邏輯
end

注意:由於 session 使用 cookie 來保存資料,因此不適用於大量或敏感資訊。

3. 使用 Flash

Flash 是一個特殊的部分 session,用於儲存會在下一個請求中消失的訊息。它通常用於像是成功或錯誤這樣的短暫訊息。

def create
  @article = Article.new(article_params)
  if @article.save
    redirect_to @article, notice: "文章已成功儲存。
  else
    render :new
  end
end

然後,在 View 中,可以這樣顯示這個訊息
(如果只寫在 controller 那只會儲存在 flash 裡,而不會顯示出來):

<%= flash[:notice] %>

請求週期(Request Cycle)是什麼?


複習一下,就是這張圖
可以參考這篇

Request Cycle 多長?

請求週期的長度會因應不同的情況而有所變化。它不是一個固定的時間單位,而是由多個因素影響的一個過程。以下是一些影響請求週期長度的因素:

  1. 網路連線品質:客戶端與伺服器之間的網路若延遲會影響 request 和 response 的時間。

  2. 伺服器效能:伺服器硬體和軟體的效能,以及當前負載(loading)狀況,都會影響處理請求的速度。

  3. 資料庫查詢:如果請求牽涉到資料庫操作,查詢效率和資料庫效能也會影響週期時間。

  4. 第三方服務:如果請求需要與第三方服務(例如 API)互動,這些服務的 response 時間也會影響整體的請求週期。

  5. 客戶端處理速度:某些請求週期也包括客戶端(如瀏覽器)渲染頁面的時間,這取決於 user 所使用裝置的效能。

  6. 程式碼效率:伺服器和客戶端程式碼的效率也會影響請求週期的長度。

由於這些多變因素,請求週期可能從幾毫秒到幾秒不等,甚至更長。在某些特殊情況下(例如文件上傳或大規模資料處理),它甚至可能需要更多時間。因此,沒有固定的「請求週期有多長」的答案。如果你希望優化請求週期,通常需要從多個層面來進行優化和調整。

狀態碼 (Status Code)是什麼? 200 OK 是什麼?302 Found 是什麼?

狀態碼是 HTTP response 的一部分,用於表示請求的處理狀態。它是一個三位數的數字,通常與一個簡短的文字描述(狀態文字)一起出現,以說明請求成功、失敗,或需要進一步的操作。

200 OK

這是一個表示成功的狀態碼。當 HTTP 請求成功被伺服器處理後,通常會返回 200 OK。這意味著請求的資源已被成功讀取、新增、修改等。

302 Found

這是一個重導(Redirection)狀態碼。當遇到這個狀態碼時,客戶端會被告知所請求的資源存在於一個不同的 URL 上,並且應該使用 GET 方法從那個 URL 重新獲取資源。這種狀態碼通常用於臨時的 URL 重導上。與之相對的是永久重導,通常使用 HTTP 狀態碼 301 Moved Permanently。表示資源已經永久地移動到了一個新的位置,並且未來都會在那裡。

簡而言之,200 OK 通常表示「一切正常,你的請求已成功」,而 302 Found 則表示「你要找的資源在別的地方,請從那裡重新讀取」。


以上!希望大家都有一些心得或想法了
gogogogogogo~~~~~~


上一篇
vol. 17 Rails 來 new 一下!熟悉一下專案流程與指令吧
下一篇
vol. 19 Rails 裡的 helper, Service Object, Concern 到底怎麼用?
系列文
富士大顆30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言