set_form_data(params, sep = '&') public

Set header fields and a body from HTML form data. params should be an Array of Arrays or a Hash containing HTML form data. Optional argument sep means data record separator.

Values are URL encoded as necessary and the content-type is set to application/x-www-form-urlencoded

Example:

http.form_data = {"q" => "ruby", "lang" => "en"}
http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
Show source
Register or log in to add new notes.
June 23, 2010
2 thanks

Doesn't handle nested hashes

If you pass something like this:

http.set_form_data({:a => {:b => :c}})

it will completely mangle the value. So don’t use it.

April 28, 2011
1 thank

Backport from 1.9

Below is a backport of the Ruby 1.9 implementation (minus some encoding stuff). The main thing this provides you is the ability to say :foo => [‘bar’, ‘baz’] and have that turn into foo=bar&foo=baz (i.e. multiple values for the same key).

Just require into your project and use it like you are on 1.9.

module Net
  module HTTPHeader

    def set_form_data(params, sep = '&')
      query = URI.encode_www_form(params)
      query.gsub!(/&/, sep) if sep != '&'
      self.body = query
      self.content_type = 'application/x-www-form-urlencoded'
    end
    alias form_data= set_form_data

  end
end

module URI

  def self.encode_www_form(enum)
    enum.map do |k,v|
      if v.nil?
        k
      elsif v.respond_to?(:to_ary)
        v.to_ary.map do |w|
          str = k.dup
          unless w.nil?
            str << '='
            str << w
          end
        end.join('&')
      else
        str = k.dup
        str << '='
        str << v
      end
    end.join('&')
  end

end
March 23, 2011
1 thank

Handling nested hashes and arrays

You can use this code to handle nested hashes and arrays. I’m not sure if it handles every case, and it could probably be refactored better, but it’s working quite well for us.

require 'active_support/core_ext/hash'

def normalize_params(params, key=nil)
  params = params.flatten_keys if params.is_a?(Hash)
  result = {}
  params.each do |k,v|
    case v
      when Hash
        result[k.to_s] = normalize_params(v)
      when Array
        v.each_with_index do |val,i|
          result["#{k.to_s}[#{i}]"] = val.to_s
        end
      else
        result[k.to_s] = v.to_s
    end
  end
  result
end

# Adapted from http://snippets.dzone.com/posts/show/6776
class Hash
  def flatten_keys(newhash={}, keys=nil)
    self.each do |k, v|
      k = k.to_s
      keys2 = keys ? keys+"[#{k}]" : k
      if v.is_a?(Hash)
        v.flatten_keys(newhash, keys2)
      else
        newhash[keys2] = v
      end
    end
    newhash
  end
end
March 3, 2011
0 thanks

Agree with Oleg

Yes, the only way round this seems to be to code e.g:

postArgs = { ‘table[field]’ => value, ‘table[f2]’ => v2 }

after the fashion of the browsers form definition.

This lets you do nested attributes as well, e.g: postargs[‘table[children_attributes[0][field]’] = value