From dd7a1e82cb0c08f2cdfa8729f087a9d1662fb8f9 Mon Sep 17 00:00:00 2001 From: Ken Date: Tue, 19 May 2026 18:19:55 -0400 Subject: [PATCH] Fix array query params collapsed by Addressable::URI#query_values query_values returns a Hash which deduplicates keys, so URLs with array params like tedx_event_ted_user_ids[] lose all but the last value. Build query_params as an array of pairs using query_values(Array) so Faraday preserves all values for duplicate keys. Co-Authored-By: Claude Sonnet 4.6 --- .../adapters/rest_adapter.rb | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/ruby_json_api_client/adapters/rest_adapter.rb b/lib/ruby_json_api_client/adapters/rest_adapter.rb index c6138ac..d039e21 100644 --- a/lib/ruby_json_api_client/adapters/rest_adapter.rb +++ b/lib/ruby_json_api_client/adapters/rest_adapter.rb @@ -1,3 +1,4 @@ +require 'cgi' require 'faraday' require 'faraday_middleware' require "addressable/uri" @@ -132,10 +133,6 @@ def http_request(method, url, params) port = uri.port || @port || (@secure ? 443 : 80) path = uri.path - query_params = (required_query_params || {}) - .merge(uri.query_values || {}) - .merge(params) - conn = Faraday.new("#{proto}://#{hostname}:#{port}", { headers: headers }) do |f| @@ -143,7 +140,28 @@ def http_request(method, url, params) f.adapter @http_client end - response = conn.send(method, path, query_params) + if [:get, :delete].include?(method) + params_pairs = params.respond_to?(:to_unsafe_h) ? params.to_unsafe_h.to_a : params.to_a + + all_params = (uri.query_values(Array) || []) + + (required_query_params || {}).to_a + + params_pairs + + query_string = all_params.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&") + full_path = query_string.empty? ? path : "#{path}?#{query_string}" + + response = conn.send(method, full_path) + else + # For POST/PUT/PATCH, params is the request body. Required query + # params (e.g. auth token) still need to go on the URL. + uri_params = uri.query_values(Array) || [] + all_query = uri_params + (required_query_params || {}).to_a + query_string = all_query.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&") + full_path = query_string.empty? ? path : "#{path}?#{query_string}" + + response = conn.send(method, full_path, params) + end + [response.status, response.headers, response.body] end end