Ruby 4.0 compatibility: CGI.parse removed in LoginProtection#return_address_with_params
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 1.9k
- Forks
- 739
- Avg merge
- 21h 2m
- Merged PRs (30d)
- 1
Description
Summary
LoginProtection#return_address_with_params calls CGI.parse which was removed from Ruby's standard library in Ruby 4.0. This causes a NoMethodError on every OAuth callback, making authentication completely broken on Ruby 4.0.
Affected versions
Confirmed broken in shopify_app 22.5.2 and 23.0.1 (per the source). Ruby 4.0.1.
Location
lib/shopify_app/controller_concerns/login_protection.rb
def return_address_with_params(params)
uri = URI(base_return_address)
uri.query = CGI.parse(uri.query.to_s) # ← NoMethodError on Ruby 4.0
.symbolize_keys
.transform_values { |v| v.one? ? v.first : v }
.merge(params)
.to_query
uri.to_s
end
Root cause
CGI was separated from Ruby's stdlib into a standalone gem in Ruby 3.4 (with a deprecation warning) and fully removed in Ruby 4.0. See ruby/cgi#82.
Suggested fix
Replace with Rack::Utils.parse_query, which is already available as a transitive dependency of Rails, returns a plain hash directly (no array-unwrapping needed), and is idiomatic for query string parsing in a Rack/Rails context:
def return_address_with_params(params)
uri = URI(base_return_address)
uri.query = Rack::Utils.parse_query(uri.query.to_s)
.symbolize_keys
.merge(params)
.to_query
uri.to_s
end
This is cleaner than the original because Rack::Utils.parse_query returns string values directly (not arrays), so the .transform_values unwrapping step is no longer needed.
Alternatives considered
- Add
gem 'cgi'to the gemspec: Would restoreCGI.parsewithout code changes, but adds an external dependency purely to keep an awkward API that wraps every value in an array. URI.decode_www_form(...).to_h: Pure stdlib, no extra deps, but more verbose than the Rack alternative.
Workaround
Apps running Ruby 4.0 can monkey-patch the method in an initializer:
# config/initializers/shopify_app_ruby4_compat.rb
module ShopifyApp
module LoginProtection
private
def return_address_with_params(params)
uri = URI(base_return_address)
uri.query = URI.decode_www_form(uri.query.to_s).to_h
.transform_keys(&:to_sym)
.merge(params)
.to_query
uri.to_s
end
end
end
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with lib/shopify_app/controller_concerns/login_protection.rb and the return_address_with_params entry point. Reproduce the OAuth callback failure on Ruby 4.0, then verify that query parameters still merge into the return address without NoMethodError. Done means Ruby 4.0 compatibility is restored while preserving the existing URL behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rails, ruby
- Domain
- authentication
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100