set_form_data
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"}, ';')
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.
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
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
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