What is the most elegant way in Ruby to remove a parameter from a URL?

Viewed 15365

I would like to take out a parameter from a URL by its name without knowing which parameter it is, and reassemble the URL again.

I guess it is not that hard to write something on my own using CGI or URI, but I imagine such functionality exists already. Any suggestions?

In:

http://example.com/path?param1=one&param2=2&param3=something3

Out:

http://example.com/path?param2=2&param3=something3
7 Answers

The addressable gem will do this nicely; please see the superior answer by The Tin Man. But if you want to roll your own, here's how. The only claim this code has to elegance is that it hides the ugly in a method:

#!/usr/bin/ruby1.8

def reject_param(url, param_to_reject)
  # Regex from RFC3986
  url_regex = %r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$"
  raise "Not a url: #{url}" unless url =~ url_regex
  scheme_plus_punctuation = $1
  authority_with_punctuation = $3
  path = $5
  query = $7
  fragment = $9
  query = query.split('&').reject do |param|
    param_name = param.split(/[=;]/).first
    param_name == param_to_reject
  end.join('&')
  [scheme_plus_punctuation, authority_with_punctuation, path, '?', query, fragment].join
end   

url = "http://example.com/path?param1=one&param2=2&param3=something3"
p url
p reject_param(url, 'param2')

# => "http://example.com/path?param1=one&param2=2&param3=something3"
# => "http://example.com/path?param1=one&param3=something3"

I came up with something like this

 def uri_remove_param(uri, params = nil)
   return uri unless params
   params = Array(params)
   uri_parsed = URI.parse(uri)
   return uri unless uri_parsed.query
   escaped = uri_parsed.query.grep(/&/).size > 0
   new_params = uri_parsed.query.gsub(/&/, '&').split('&').reject { |q| params.include?(q.split('=').first) }
   uri = uri.split('?').first
   amp = escaped ? '&' : '&'
   "#{uri}?#{new_params.join(amp)}"
 end

Here's a clean one if your url is a string:

  def remove_param(url, param_name)
    uri = URI(url)
    params = []
    URI.decode_www_form(uri.query || '').each do |param|
      next if param[0] == param_name

      params << param
    end
    uri.query = URI.encode_www_form(params)
    uri.to_s
  end

note: you could use this to remove a param with a specific value by changing:

def remove_param(url, param_value)

and

next if param[1] == param_value
Related