159

I have some URLs, like

http://www.example.com/something?param1=value1&param2=value2&param3=value3

and I would like to extract the parameters from these URLs and get them in a Hash. Obviously, I could use regular expressions, but I was just wondering if there was easier ways to do that with Ruby or Rails. I haven't found anything in the Ruby module URI but perhaps I missed something.

In fact, I need a method that would do that:

extract_parameters_from_url("http://www.example.com/something?param1=value1&param2=value2&param3=value3")
#=> {:param1 => 'value1', :param2 => 'value2', :param3 => 'value3'}

Would you have some advices?

1
  • 1
    Hash[*string.split('&').collect{|i|i.split('=')}.flatten] This would work too, but it's probably the worst option for this case. But still you might find this snippet interesting. (Posting as comment since I don't consider this an answer :-)) Commented Jul 10, 2010 at 5:53

11 Answers 11

192

I think you want to turn any given URL string into a HASH?

You can try http://www.ruby-doc.org/stdlib/libdoc/cgi/rdoc/classes/CGI.html#M000075

require 'cgi'

CGI::parse('param1=value1&param2=value2&param3=value3')

returns

{"param1"=>["value1"], "param2"=>["value2"], "param3"=>["value3"]}
Sign up to request clarification or add additional context in comments.

5 Comments

OK, that was the one I missed! It's perfect when used with URI.parse : CGI.parse(URI.parse("example.com/…) returns the desired Hash. Thanks for your help.
For clarity, @Flackou wants this: CGI.parse(URI.parse(url).query)
I haven't tested this, but the first key listed, containing the full url, seems really wrong.
I actually had to use this: CGI::parse(URI::parse(url).query)
This solution won't work properly with arrays, like a[]=1&a[]=2 will be parsed as {"a[]"=>["1", "2"]} whereas Arthur's solution will parse {"a"=>["1", "2"]}
182

I found myself needing the same thing for a recent project. Building on Levi's solution, here's a cleaner and faster method:

Rack::Utils.parse_nested_query 'param1=value1&param2=value2&param3=value3'
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}

5 Comments

Much more lightweight than mocking a Rack request
Good find. If you have simple params (non-nested) and are performance sensitive, Rack::Utils.parse_query might be of interest. The code is worth reading: github.com/rack/rack/blob/master/lib/rack/utils.rb
This works well but does not work for checkboxes with the same name: param1=value1&param1=value2. The second value trumps the first.
For anyone looking for the inverse, it's Rack::Utils.build_nested_query(params) (or Rack::Utils.build_query(params) if parsed with Rack::Utils.parse_query).
This method crashes sometimes because of encoding issues. I found the CGI:parse method to be more stable (see answer above)
117

Just Improved with Levi answer above -

Rack::Utils.parse_query URI("http://example.com?par=hello&par2=bye").query

For a string like above url, it will return

{ "par" => "hello", "par2" => "bye" } 

4 Comments

great answer. simple, processes the full URL like the op asks, and the result values are strings instead of arrays, like in the other answers. thanks.
As I commented above, for anyone looking for the inverse, it's Rack::Utils.build_query(params).
Beware - not quite the inverse, at least not in Ruby 1.8.7 / Rails 2.3. A query string of foo[]=1&foo[]=2 is correctly parsed as { "foo" =>["1","2"] }, but build_query turns that into "foo=1&foo=2", which when parsed again yields { "foo"=>"2"}.
Took me a minute to realize that due to lack of wrapping params, this answer isn't readily extended. Rack::Utils.parse_query(URI("http://example.com?par=hello&par2=bye").query) yields a hash that can be further modified.
56

For a pure Ruby solution combine URI.parse with CGI.parse (this can be used even if Rails/Rack etc. are not required):

CGI.parse(URI.parse(url).query) 
# =>  {"name1" => ["value1"], "name2" => ["value1", "value2", ...] }

1 Comment

This is elegant.
44

There more than one ways, to solve your problem. Others has shown you the some tricks. I know another trick. Here is my try :-

require 'uri'
url = "http://www.example.com/something?param1=value1&param2=value2&param3=value3"
uri = URI(url)
# => #<URI::HTTP:0x89e4898 URL:http://www.example.com/something?param1=value1&param2=value2&param3=value3>
URI::decode_www_form(uri.query).to_h # if you are in 2.1 or later version of Ruby
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}
Hash[URI::decode_www_form(uri.query)] # if you are below 2.1 version of Ruby
# => {"param1"=>"value1", "param2"=>"value2", "param3"=>"value3"}

Read the method docomentation of ::decode_www_form.

Comments

16

Check out the addressable gem - a popular replacement for Ruby's URI module that makes query parsing easy:

require "addressable/uri"
uri = Addressable::URI.parse("http://www.example.com/something?param1=value1&param2=value2&param3=value3")
uri.query_values['param1']
=> 'value1'

(It also apparently handles param encoding/decoding, unlike URI)

1 Comment

Sadly it looks this gem, like the URI library, has difficulty parsing query parameters in situations where the URL is weird. I.e. both fail to find query parameters when urls are odd, e.g. this: http://localhost:4300/webapp/foo/#//controller/action? Leaving me to use a hack like: Rack::Utils.parse_nested_query(url.split("?").last) to get the query parameters for parsing.
8

Using CGI might be an outdated approach with Ruby 2.7/3.

Here's a neat way to do this with URI:

uri = URI.parse 'https://duckduckgo.com/?q=ruby+programming+language'
params = Hash[URI.decode_www_form uri.query]
# => {"q"=>"ruby programming language"} 

1 Comment

Look, no additional libraries needed 👍
2

you can also use this method


require 'uri'
require 'cgi'
uri = URI("https://example.com/?query=1&q=2&query=5")
a = CGI::parse(uri.query)
puts a                   #=> {"query"=>["1", "5"], "q"=>["2"]}
puts a["query"].to_s     #=> ["1", "5"]
puts a["query"][0]       #=>  1
puts a["query"][1]       #=>  5
puts a["q"][0]           #=>  2


its safe and much easier

Comments

2

Sadly both the URI and addressable libraries break when attempting to extract query params from buggy URLs. E.g. this breaks both:

http://localhost:4300/webapp/foo/#//controller/action?account=001-001-111&email=john%40email.com

Building on Arthur / Levi's solution, with url.split("?").try(:last) you can grab just the query param portion of the URL, and use Rack::Utils.parse_nested_query to parse that string of parameters into a hash.

Or in full:

Rack::Utils.parse_nested_query(url.split("?").try(:last))

returning in my example:

{"account": "001-001-111", "email": "[email protected]"}

Comments

0

The above answers are very well written and they serve the purpose, however I tried some query manipulation and wanted to share here. So, here is my take:

   URI("http://example.com?par=hello&par2=bye").query.split('&').map { |param| {query_param: param.split('=')[0] , value: param.split('=')[1]}  }

It serves the purpose and return an array of objects for each query param. Having said that, please keep in mind the COC principle of ROR.

Comments

-4

In your Controller, you should be able to access a dictionary (hash) called params. So, if you know what the names of each query parameter is, then just do params[:param1] to access it... If you don't know what the names of the parameters are, you could traverse the dictionary and get the keys.

Some simple examples here.

1 Comment

OK, I knew that, it works well in the controller with the requested URL, but how to do that for others arbitrary URLs?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.