|
| 1 | +`Rack::Test` defaults to URL Encoding Parameters |
| 2 | +================================================ |
| 3 | + |
| 4 | +By default, Rack's test helpers set the `Content-Type` header to |
| 5 | +`application/x-www-form-urlencoded`. |
| 6 | + |
| 7 | +The URL encoded representation of |
| 8 | + |
| 9 | +```json |
| 10 | +{ "tags": ["foo", "bar"] } |
| 11 | +``` |
| 12 | + |
| 13 | +would be |
| 14 | + |
| 15 | +``` |
| 16 | +?tags[]=foo&tags[]=bar |
| 17 | +``` |
| 18 | + |
| 19 | +This works as expected for non-empty arrays: |
| 20 | + |
| 21 | +```ruby |
| 22 | +put "/api/v1/post/1", { |
| 23 | + post: { tags: ["foo"] } |
| 24 | +} |
| 25 | +``` |
| 26 | + |
| 27 | +However, it isn't possible to represent `[]` as a URL encoded string. |
| 28 | + |
| 29 | +```ruby |
| 30 | +put "/api/v1/post/1", { |
| 31 | + post: { tags: [] } |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +would be invalidly encoded as: |
| 36 | + |
| 37 | +``` |
| 38 | +?tags[]= |
| 39 | +``` |
| 40 | + |
| 41 | +As a result, Rack ignores the `tags` key, which would make the `post` key point |
| 42 | +to an empty hash, which Rack also ignores. |
| 43 | + |
| 44 | +To work around this issue: |
| 45 | + |
| 46 | +* transform the `params` hash to a [`JSON` string][rack-test] |
| 47 | +* append `.json` to the URL |
| 48 | +* explicitly set the `"Content-Type"` header to `"application/json"` |
| 49 | + |
| 50 | +```ruby |
| 51 | +put "/api/v1/post/1.json", { |
| 52 | + post: { tags: [] } |
| 53 | +}.to_json, { "Content-Type" => "application.json" } |
| 54 | +``` |
| 55 | + |
| 56 | +This pattern can be extracted to a helper: |
| 57 | + |
| 58 | +```ruby |
| 59 | +def json_put(path, params, headers_or_env = {}) |
| 60 | + json_path = "#{path}.json" |
| 61 | + params_without_format = params.except(:format) |
| 62 | + headers = headers_or_env.reverse_merge("Content-Type" => "application/json") |
| 63 | + |
| 64 | + put(json_path, params_without_format.to_json, headers) |
| 65 | +end |
| 66 | + |
| 67 | + |
| 68 | +json_put "/api/v1/post/1", { |
| 69 | + post: { tags: [] } |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +Coincidentally, Basecamp has a similar set of test helpers. |
| 74 | + |
| 75 | +[rack-test]: https://github.com/brynary/rack-test/blob/acdbee66fc765f15c2d3a1a372c368fe8ee0a49c/lib/rack/test.rb#L218-L228 |
0 commit comments