Skip to content

fix: replace CGI.parse with Rack::Utils.parse_query for Ruby 4.0 compatibility#2058

Open
bvogel wants to merge 2 commits intoShopify:mainfrom
bvogel:fix/ruby-4-cgi-parse-removed
Open

fix: replace CGI.parse with Rack::Utils.parse_query for Ruby 4.0 compatibility#2058
bvogel wants to merge 2 commits intoShopify:mainfrom
bvogel:fix/ruby-4-cgi-parse-removed

Conversation

@bvogel
Copy link

@bvogel bvogel commented Feb 26, 2026

Summary

Fixes #2057

CGI.parse was removed from Ruby's standard library in Ruby 4.0, causing a NoMethodError in LoginProtection#return_address_with_params on every OAuth callback. This breaks authentication entirely on Ruby 4.0 — the callback 500s before the session can be stored.

Change

Replace CGI.parse with Rack::Utils.parse_query, which is already available as a transitive dependency of Rails (no new dependency introduced).

# Before
uri.query = CGI.parse(uri.query.to_s)
  .symbolize_keys
  .transform_values { |v| v.one? ? v.first : v }
  .merge(params)
  .to_query

# After
uri.query = Rack::Utils.parse_query(uri.query.to_s)
  .symbolize_keys
  .merge(params)
  .to_query

Rack::Utils.parse_query returns a plain hash with string values directly, so the .transform_values unwrapping step (which existed to flatten CGI.parse's array-of-strings format) is no longer needed — the result is also slightly simpler.

Behaviour difference

For Shopify URL params, none. The only theoretical difference is duplicate keys: CGI.parse would collect them into an array, while Rack::Utils.parse_query keeps the last value. Shopify-generated query strings never have duplicate parameter names.

Testing

Existing test coverage for return_address_with_params should confirm correctness. Manually verified on Ruby 4.0.1 + Rails 8.1.

…atibility

CGI.parse was removed from Ruby's standard library in Ruby 4.0, causing a
NoMethodError in LoginProtection#return_address_with_params on every OAuth
callback, breaking authentication entirely on Ruby 4.0.

Replace with Rack::Utils.parse_query, which is already available as a
transitive dependency of Rails. It returns a plain hash with string values
directly, so the .transform_values unwrapping step is no longer needed either.

Fixes Shopify#2057
@bvogel bvogel requested a review from a team as a code owner February 26, 2026 16:34
@bvogel
Copy link
Author

bvogel commented Feb 26, 2026

back-porting this to the v22 branch would help a lot, as we still need to migrate to v23 for our project

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ruby 4.0 compatibility: CGI.parse removed in LoginProtection#return_address_with_params

1 participant