Skip to content

Instantly share code, notes, and snippets.

@rbotzer
Created May 10, 2010 22:54
Show Gist options
  • Save rbotzer/396648 to your computer and use it in GitHub Desktop.
Save rbotzer/396648 to your computer and use it in GitHub Desktop.

Query Parsing in Ruby

While looking for a Ruby equivalent of PHP's parse_query(), or Python's urlparse.parse_qs (i.e. the reverse of ActiveSupport's Object#to_query extension), I ran into several limited/failed implementations. Addressable is the only one that seems to do it right.

Examples for common datatypes

>> require 'active_support'
>> str_ex = "bar".to_query('foo')
=> "foo=bar"
>> array_ex = [1, 2, 3].to_query('foo')
=> "foo%5B%5D=1&foo%5B%5D=2&foo%5B%5D=3"
>> CGI.unescape(array_ex)
=> "foo[]=1&foo[]=2&foo[]=3"
>> hash_ex = {'a' => 1, 'b' => 2}.to_query('foo')
=> "foo%5Ba%5D=1&foo%5Bb%5D=2"
>> CGI.unescape(hash_ex)
=> "foo[a]=1&foo[b]=2"

CGI gets it wrong

>> require 'cgi'
>> CGI.parse(str_ex)
=> {"foo"=>["bar"]}
>> CGI.parse(array_ex)
=> {"foo[]"=>["1", "2", "3"]}
>> CGI.parse(hash_ex)
=> {"foo[b]"=>["2"], "foo[a]"=>["1"]}

Rack::Utils gets it wrong

>> require 'rack/utils'
>> Rack::Utils.parse_query(str_ex)
=> {"foo"=>"bar"}
>> Rack::Utils.parse_query(array_ex)
=> {"foo[]"=>["1", "2", "3"]}
>> Rack::Utils.parse_query(hash_ex)
=> {"foo[b]"=>"2", "foo[a]"=>"1"}

Addressable gets it right

>> require 'addressable/uri'
>> Addressable::URI.parse("/?#{array_ex}").query_values()
=> {"foo"=>["1", "2", "3"]}
>> Addressable::URI.parse("/?#{str_ex}").query_values()
=> {"foo"=>"bar"}
>> Addressable::URI.parse("/?#{array_ex}").query_values()
=> {"foo"=>["1", "2", "3"]}
>> Addressable::URI.parse("/?#{hash_ex}").query_values()
=> {"foo"=>{"a"=>"1", "b"=>"2"}}
>> Addressable::URI.parse("/?e=5&a[]=1&a[]=2&b['c']=3&b['d']=4").query_values()
=> {"a"=>["1", "2"], "b"=>{"'c'"=>"3", "'d'"=>"4"}, "e"=>"5"}

NOTE: Sinatra does this correctly as part of the get/post DSL declarations, but has no static method for parsing a String.

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