Rails Requests and Params

陳漢庭
5 min readOct 3, 2020

--

在 Rails 中,Web requests 是透過Action ControllerAction Viewer 來處理,一般來說 Action Controller 關注的是和資料庫溝通以及處理 CRUD;Action View 則負責編譯要回傳的 response。

初學Rails的時候,因為form_for, simple_form_for等rails helper讓我不太知道rails做了什麼,對params實在是一竅不通,沒有辦法活用。那時候主管出給我跟另外一個Junior其中一個功課就是了解Rails Controller, View之間做了什麼事情,作業的內容包括View的資料怎麼到Controller的,以及Rails CSRF Token是什麼東西等。這幾個問題到後來影響我非常深,因為在第二份工作時碰到了很多表單問題,以及表單很多很動態的需求沒有辦法單單只靠simple_form解決,需要更多原生的表單概念。當然現在也不能說自己真的懂了很多,像是對於controller的request, response是什麼東西都還不太了解。

Params

以get來說的話,Controller識別的就是query parameters,或者是route上面的:id值。有幾種狀況會需要,像是edit, show, update這三個方法會利用:id找到某一筆資料,而另外一種狀況是在搜尋的時候給予query parameters,例如/admin/faqs?a=1&b=2,我們利用傳入Controller的 a: 1, b: 2來去找我們的資料。

以post來說就分兩種了,一種為api打入而另外一種是form表單的傳入。首先先講打api的部分,以下圖api為例,我們送出了一個post request,post body的格式為下方大框框住的那種形式,進去params的樣子也會是一樣的長相。

上面這種情況是我自己意外中發現的,當沒有特地拼成strong params的形狀,它進去controller的資料竟然為下列的形式,讓我不禁覺得Rails有各種黑魔法存在(現在還不知道為什麼,反正有的話用就對了)。

{
:account_name => "...",
:bank_code => "...",
:branch_name: "...",
:account => "...",
:a => "b",
:c => "d",
:[controller名字] => {
:account_name => "...",
:bank_code => "...",
:branch_name: "...",
:account => "...",
:a => "b",
:c => "d",
}
}

另外一種形式為Rails表單發送,首先表單發送時Rails會使用CSRF Token識別表單是不是從畫面上送出的,以防止Rails受到外部控制。再來其他傳入rails表單的params key會由html name attribute所決定,比方說一個html tag叫做

<form action="/..." method="post">
...
<input type="hidden" name="client[name]" value="Acme" />
</form>

那傳進去controller的值其中有個值將為 {:client => {:name => “Acme”}}。那種這一塊的話simple_form, form都幫忙做好了,所以如果從rails初學的話會不知道這是什麼東西。在工作上若要把設計寫好的html稿謄寫在後台上、使用JS做DOM渲染,或者輕量化的使用vue表單,那name attributes就一定要知道。

關於params的內容在這一篇都有講到。那rails guide裡面也寫了很多詳細的狀況,但rails guide對rails稍微熟悉一點的人看起來比較不會那麼吃力。

這篇對params的詮釋還蠻好的

Request

再來介紹controller的特殊參數request與一些神奇的用法。

request 有很多方法可以使用,我自己常用的方法為以下這幾種:

  • request.host
  • request.path
  • request.domain
  • request.referrer
  • request.base_url
  • request.subdomain
  • request.original_url
  • request.ip / request.remote_ip
  • request.params, request.parameters

像如果我想要返回前一頁,我都會使用request.referrer ,如果有些功能為用子網域去分的,比方說admin.hanting.com, api.hanting.com就可以使用request.subdomain去判斷。

曾經踩過的雷

  1. ActionController::ParameterMissing(忘記怎麼踩的了): Link

--

--

陳漢庭
陳漢庭

Written by 陳漢庭

由於零散的紀錄過了一段時間之後就看不懂了,於是為了強迫自己用故事的方式記錄學到的東西,就開啟我的發文之路。

No responses yet