什麼是params
params是一個包含用戶所有傳進來的參數Hash(事實上params是來自於ActiveSupport::HashWithIndifferentAccess的object)。
一個params,至少一定會包含:controller和:action兩個key。我們可以直接透過params知道這個request是對應哪個controller跟action
# 對pages/index送出請求後得到的params
=> <ActionController::Parameters {"controller"=>"pages", "action"=>"index"} permitted: false>
兩種params來源
Rails透過兩種方式來透過params傳遞訊息,Query String參數或 POST參數。而在Rails並不區分,兩者都可以在controller中被取用。我們待會會針對兩種方式分別介紹。
Query String Parameters
第一種是透過url,又稱做作query string parameters。Query String 是url中?號後面的任何字串,通常是透過HTTP GET傳遞。
舉例來說,當我們對以下的url送出請求
localhost:3000/pages?state=cool
我們可以得到以下的params
params
=> <ActionController::Parameters {"state"=>"cool", "controller"=>"pages", "action"=>"index"} permitted: false>
使用form表單送出get request
假設你使用get的form表單,你也可以透過query string parameters來傳遞訊息到params中。
<%= form_tag "/", method: :get do %>
<%= label_tag :name %>
<%= text_field_tag :name %>
<%= label_tag :age %>
<%= text_field_tag :age %>
<%= submit_tag "Submit" %>
<% end %>
接著在controller中下byebug
class PagesController < ApplicationController
def index
byebug
end
end
頁面看起來像這樣
送出請求後在byebug停下來的地方下params指令會得到
<ActionController::Parameters {"utf8"=>"✓", "name"=>"Franklin Graham", "age"=>"43", "commit"=>"Submit", "controller"=>"homes", "action"=>"show"} permitted: false>
讓指令繼續跑完,照理說你的url會變成這樣
所以即使你是透過form表單送出get request,最後也是變成query string parameters的方式傳遞訊息。
HTTP Post
另外一種傳遞params的方式,是透過Rails的HTTP Post方法。
讓我們建立一個表單和對應的action。
<%= form_for @page do |f| %>
<%= f.label :user %>
<%= f.text_field :user %>
<%= f.submit "送出" %>
<% end %>
# controller/pages_controller.rb
Class PagesController < ApplicationController
def create
@page = Page.new(page_params)
@page.save
end
end
而我們在controller可以得到params如下
params
=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"nZgtu+hFRmIbLcZU+uVcfRLdXXYW0J4U005GzeoCFu2eY9kW7Nu2niJu9Bf+aCvCxlsc2QclvCQGzBYU5z2+xQ==", "page"=>{"user"=>"Elon Musk"}, "commit"=>"送出", "controller"=>"pages", "action"=>"create"} permitted: false>
如果你仔細觀察的話你會發現,透過query string parameter跟Post request傳遞的params基本上沒有太大的差異,這也是為什麼我們說Rails並不區分兩者的原因。
Hash and Array Parameters
如果想要在params中產生nested array的話,你可以這樣做
https://example.com/clients?ids[]=1&ids[]=2&ids[]=3
這樣的話,透過params我們就可以得到
params[:ids]
=> ["1", "2", "3"]
<form accept-charset="UTF-8" action="/clients" method="post">
<input type="text" name="client[name]" value="Acme" />
<input type="text" name="client[phone]" value="12345" />
<input type="text" name="client[address][postcode]" value="12345" />
<input type="text" name="client[address][city]" value="Carrot City" />
</form>
When this form is submitted, the value of params[:client] will be { "name" => "Acme", "phone" => "12345", "address" => { "postcode" => "12345", "city" => "Carrot City" } }. Note the nested hash in params[:client][:address].
路徑路由(Routing Parameters)
前面提到了兩種不同傳遞params的方式,這邊我們介紹透過路由的設定,達到預先設定params的key和value的方法。
另外,還會講解path
預先設定key
先讓我們設定以下的路徑
get '/pages/:status' => 'pages#index'
當使用者送出一個get request到/clients/active
時,params[:state]的value就會被設定成active。
所以我們可以透過params得到
params[:state]
=> "active"
預先設定key、value
依舊是跟剛剛相同的路由,但我們而外加入一個hash{foo: bar}
get '/pages/:status' => 'pages#index', foo: 'bar'
這樣params[:foo]就會被設定成"bar"
params[:foo]
=> "bar"
傳遞參數到url helper中
寫過一段時間Rails的人,一定對這樣的寫法感到不陌生
link_to "Edit Page", edit_page_path(@page)
當我們點擊了Edit Page
之後,我們基本上會被帶到以下的網址。
localhost:3000/pages/3/edit
我們可以仔細觀查這個路由的uri pattern
/pages/:id/edit(.:format)
這表示當我們把object塞到path裡時,這個edit_page_path會透過塞進來的object,得到該object的id,並產生對應的路由。也就是說edit_page_path(@page)會變成
edit_page_path(@page)
=> localhost:3000/pages/3/edit
雖然這個效果很方便,但這神奇的效果是怎麼做到的?
這個效果是因為在產生路徑的過程當中,Rails會觸發一個to_params
的方法,將object轉換成該object的id。
def to_param
id && id.to_s
end
此外,我們也可以另外path設定額外的params key和value。
edit_page_path(@page, state: "active")
=> localhost:3000/pages/3/edit?state=active
@linjiahung, 这就是文章该有的气质!