Search code examples
rubyuriaddressables

URI Equivalent of encode_www_form_component in Addressable


What is the equivalent method for URI.encode_www_form_component in Addressable::URI?


Solution

  • The closest you can get is to use the #encode_component method. Beware that Addressable will use full percentage mode, and replace a space with %20 instead of +:

    Addressable::URI.encode_component('a decoded string with [email protected]', Addressable::URI::CharacterClasses::UNRESERVED)
    # => "a%20decoded%20string%20with%20email%40example.com"
    
    URI.encode_www_form_component('a decoded string with [email protected]')
    # => "a+decoded+string+with+email%40example.com"
    

    If you compare the two methods that encode a full set of key/value parameters, you will see instead that they behave more similarly:

    [15] pry(main)> Addressable::URI.form_encode([["q", "a decoded string with [email protected]"]])
    => "q=a+decoded+string+with+email%40example.com"
    [16] pry(main)> URI.encode_www_form([["q", "a decoded string with [email protected]"]])
    => "q=a+decoded+string+with+email%40example.com"
    

    I was actually surprised when I tested it. So I dug into the source code of Addressable, and I found the form_encode method makes an explicit replacement of %20 with +:

    escaped_form_values = form_values.map do |(key, value)|
      # Line breaks are CRLF pairs
      [
        self.encode_component(
          key.gsub(/(\r\n|\n|\r)/, "\r\n"),
          CharacterClasses::UNRESERVED
        ).gsub("%20", "+"),
        self.encode_component(
          value.gsub(/(\r\n|\n|\r)/, "\r\n"),
          CharacterClasses::UNRESERVED
        ).gsub("%20", "+")
      ]
    end
    

    So here's your options:

    1. Use #encode_component as it is
    2. Use #encode_component and explicitly replace %20 with + if you need to reproduce the same output
    3. Use #form_encode if you have a key/value form fields