19

How to construct URI object with query arguments by passing hash?

I can generate query with:

URI::HTTPS.build(host: 'example.com', query: "a=#{hash[:a]}, b=#{[hash:b]}")

which generates

https://example.com?a=argument1&b=argument2

however I think constructing query string for many arguments would be unreadable and hard to maintain. I would like to construct query string by passing hash. Like in example below:

hash = {
  a: 'argument1',
  b: 'argument2'
  #... dozen more arguments
}
URI::HTTPS.build(host: 'example.com', query: hash)

which raises

NoMethodError: undefined method `to_str' for {:a=>"argument1", :b=>"argument2"}:Hash

Is it possible to construct query string based on hash using URI api? I don't want to monkey patch hash object...

3 Answers 3

29

If you have ActiveSupport, just call '#to_query' on hash.

hash = {
  a: 'argument1',
  b: 'argument2'
  #... dozen more arguments
}
URI::HTTPS.build(host: 'example.com', query: hash.to_query)

=> https://example.com?a=argument1&b=argument2

If you are not using rails remember to require 'uri'

Sign up to request clarification or add additional context in comments.

3 Comments

to_query is a Rails only method. It does not exist in Ruby.
@marc_ferna questions has ruby on rails tag. You can include : ActiveSupport in non-rails projects
This is OK if you're constructing URLs for querying a Rails app; for anything else, use URI.encode_www_form as per Grizz's answer. Compare for instance {q: [1, 2]}.to_query vs URI.encode_www_form({q: [1, 2]}) — the former injects square brackets into the parameter names, a weird Rails-ism, producing q%5B%5D=1&q%5B%5D=2; while the second produces the web-standard (and much more legible) "q=1&q=2". It will also sort the keys first, which while not a showstopper, can be unnecessarily annoying to debug.
27

For those not using Rails or Active Support, the solution using the Ruby standard library is

hash = {
  a: 'argument1',
  b: 'argument2'
}
URI::HTTPS.build(host: 'example.com', query: URI.encode_www_form(hash))
=> #<URI::HTTPS https://example.com?a=argument1&b=argument2>

1 Comment

This should be the accepted answer, much better than ActiveSupport's quirky to_query for anything other than querying a Rails server.
0

You can try my iri gem, which is exactly the builder of URI/URL:

require 'iri'
uri = Iri.new
  .host('example.com')
  .add(a: 'argument1')
  .add(b: 'argument2')
  .to_s

Comments

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.