Try   HackMD

Passing Array within query string in Rails

TL;DR
Edgerails

GET /clients?ids[]=1&ids[]=2&ids[]=3 #=> params[:ids] = ["1", "2", "3"]

最近想在 GET request 裡面塞個 array 當作參數
可是在 rails 後端接到的 params 裡面只出現了最後一個值

# from frontend { date_range: ['2020-11-11', '2020-11-11'], } # in controller { "date_range" => "2020-11-11", }

於是就來研究為啥會這樣子拉


前端檢查了一遍發現沒有問題,date_range都是以Array的方式活著直到
它被傳給了 rails

這個前端的專案架構每個 request 都會先經過一層 rails 後端做包裝之後,才打去真正的 rails 後端。

於是跑來檢查第一層是不是做了什麼事情

params.permit!.to_h.symbolize_keys { date_range: ['2020-11-11', '2020-11-11'] }

堪稱完美


只好來看看是怎麼打到真正的後端的

HTTP.headers(xxx: "XXX").public_send("GET", url, params: params)

看起來是用了 http 這個 Gem 來做 API 的處理
那是不是httpparams做了什麼事情讓他壞掉的呢?
於是找到了http的 source code

# 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::Uriquery_values方法,這個方法是addressable偷過來的

def_delegators :@uri, :query_values, :query_values=

會被正確的轉成Array格式的query string,詳情見連結原始碼


那為什麼本機這邊運行的會有問題呢?有可能是 Gem 的版本過舊導致的問題,所以就跑去找了http的檔案,在client.rb裡面發現這邊處理的方式不太一樣

# 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::Uriform_encode方法,看起來也挺好的,實測發現在這邊也有正確的被轉成Array

最後就只能懷疑是Rails搞的鬼拉,於是在官方文件發現了以下這段

# 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實測:

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" }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

於是最後愉快地把key後面加上[]之後就成功地在 Rails GET request 的 query string 裡塞進Array


其他框架也有類似問題:
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)