{%hackmd theme-dark %} # Passing Array within query string in Rails TL;DR [Edgerails](https://edgeguides.rubyonrails.org/action_controller_overview.html#hash-and-array-parameters) ```ruby= GET /clients?ids[]=1&ids[]=2&ids[]=3 #=> params[:ids] = ["1", "2", "3"] ``` --- 最近想在 GET request 裡面塞個 array 當作參數 可是在 rails 後端接到的 params 裡面只出現了最後一個值 ```ruby= # from frontend { date_range: ['2020-11-11', '2020-11-11'], } # in controller { "date_range" => "2020-11-11", } ``` 於是就來研究為啥會這樣子拉 ... ... 前端檢查了一遍發現沒有問題,`date_range`都是以`Array`的方式活著直到... 它被傳給了 rails 這個前端的專案架構每個 request 都會先經過一層 rails 後端做包裝之後,才打去真正的 rails 後端。 於是跑來檢查第一層是不是做了什麼事情 ```ruby= params.permit!.to_h.symbolize_keys { date_range: ['2020-11-11', '2020-11-11'] } ``` ...堪稱完美 --- 只好來看看是怎麼打到真正的後端的 ```ruby= HTTP.headers(xxx: "XXX").public_send("GET", url, params: params) ``` 看起來是用了 `http` 這個 Gem 來做 API 的處理 那是不是`http`對`params`做了什麼事情讓他壞掉的呢? 於是找到了`http`的 source code... ```ruby= # https://github.com/httprb/http/blob/6f5ea22c44f31754c9c280825e9dd0da59cb6980/lib/http/client.rb#L145 uri.query_values = uri.query_values(Array).to_a.concat(opts.params.to_a) if opts.params && !opts.params.empty? ``` 看起來這邊是用了`HTTP::Uri`的`query_values`方法,這個方法是[從`addressable`偷過來的](https://github.com/sporkmonger/addressable/blob/f839fb28344567c792e148d7a74c529748455d11/lib/addressable/uri.rb#L1663) ```ruby= def_delegators :@uri, :query_values, :query_values= ``` 會被正確的轉成`Array`格式的`query string`,詳情見連結原始碼 --- 那為什麼本機這邊運行的會有問題呢?有可能是 Gem 的版本過舊導致的問題,所以就跑去找了`http`的檔案,在`client.rb`裡面發現這邊處理的方式不太一樣 ```ruby= # path-to-local-gems/gems/http-2.2.2/lib/http/client.rb#L123 uri.query = [uri.query, HTTP::URI.form_encode(opts.params)].compact.join("&") ``` 這邊使用的是`HTTP::Uri`的`form_encode`方法,看起來也挺好的,實測發現在這邊也有正確的被轉成`Array` 最後就只能懷疑是`Rails`搞的鬼拉,於是在[官方文件](https://edgeguides.rubyonrails.org/action_controller_overview.html#hash-and-array-parameters)發現了以下這段 ```ruby= # To send an array of values, append an empty pair of square brackets "[]" to the key name: GET /clients?ids[]=1&ids[]=2&ids[]=3 ``` --- 使用Postman實測: ```ruby= GET /clients?ids=1&ids=2&ids=3 #=> { "clients" => "3" } GET /clients?ids[]=1&ids[]=2&ids[]=3 #=> { "clients" => ["1", "2", "3"] } GET /clients?ids=1,2,3 #=> { "clients" => "1,2,3" } ``` :100: :muscle: :tada: 於是最後愉快地把key後面加上`[]`之後就成功地在 Rails GET request 的 query string 裡塞進`Array`了 --- 其他框架也有類似問題: [PHP](https://stackoverflow.com/questions/6243051/how-to-pass-an-array-within-a-query-string) ```php= ?cars[]=Saab&cars[]=Audi (Best way- PHP reads this into an array) ?cars=Saab&cars=Audi (Bad way- PHP will only register last value) ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up