0

I've got a hash and I've found that with net/http posting I have to convert it into a flat format.

Example

invoice = { :no => "100", :date => "08/08/2022", :client => {:name => "Foo" } }

Would become

params = { "invoice[no]" => "100", "invoice[date]" => "08/08/2022", "invoice[client][name]" => "Foo" }

Is there a way to do this automatically? I've tried to_param & to_query, flatten and encode_www_form but they don't convert it to this required format.

The post action I'm doing is to a Ruby On Rails backend which I use Devise Tokens to authorise.

res = Net::HTTP.post_form(uri, params)
mechnicov
  • 12,025
  • 4
  • 33
  • 56
map7
  • 5,096
  • 6
  • 65
  • 128
  • you can also convert to a JSON object (string) and send it without flattening. Of course, you have to convert back to a hash on server. – Les Nightingill Aug 30 '22 at 04:25
  • I get the error "encode_www_form: undefined method map for" if I try passing the hash as json in the `Net::HTTP.post_form(uri, invoice.to_json)` – map7 Aug 30 '22 at 05:12

2 Answers2

3

You need CGI.parse method. It parses an HTTP query string into a hash of key => value pairs

CGI.parse({ invoice: invoice }.to_query)

# => {"invoice[client][name]"=>["Foo"], "invoice[date]"=>["08/08/2022"], "invoice[no]"=>["100"]

Don't care about single-element arrays as values. It will works well

params = CGI.parse({ invoice: invoice }.to_query)
res = Net::HTTP.post_form(uri, params)
mechnicov
  • 12,025
  • 4
  • 33
  • 56
0

I think this snippet should do the job:

invoice = { :no => "100", :date => "08/08/2022", :client => {:name => "Foo" } }

CGI.unescape({invoice:}.to_query)
   .split('&')
   .map{ |p| p.split('=') }
   .to_h

{"invoice[client][name]"=>"Foo", "invoice[date]"=>"08/08/2022", "invoice[no]"=>"100"}

First of all, we let ActiveRecord generate the query-like structure from a hash using the method to_query. We need to unescape the query string afterward since we don't want to have URL-encoded output there. After that we split the string by parameter using split('&') and every parameter into key-value using split('='). Finally, we convert the output back into a hash.

Bustikiller
  • 2,423
  • 2
  • 16
  • 34