Ruby/Rails Net::HTTP.post_form nested hash items html escaped - ruby-on-rails

Example I am doing this in rails console:
params = {"type"=>["raka"], "fields"=>["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0", "t2", "t3", "t4"], "railing"=>["A-3"], "wood"=>["wood_6"], "railing_m"=>"0", "order"=>{"sving"=>"right", "size"=>{"ground"=>"123", "floor"=>"6", "a"=>"6", "d"=>"6"}, "comments"=>{"step_2"=>"", "step_3"=>"", "step_4"=>""}, "railing"=>{"1"=>"1", "2"=>"1"}, "railing_m"=>{"1"=>"", "2"=>"", "3"=>"", "4"=>"12"}, "hul"=>{"l"=>"123", "b"=>"123"}, "name"=>"qwed", "email"=>"mail#example.com", "phone"=>"13123", "street"=>"iuuj", "city"=>"ui", "postnr"=>"213"}}
x = Net::HTTP.post_form(URI.parse('http://localhost:3000/download.pdf'), params)
In my Rails console I can see the HTTP post request:
Started POST "/download.pdf" for 127.0.0.1 at 2013-04-15 16:25:36 +0200
Processing by PublicController#show_pdf as */*
Parameters: {"type"=>"raka", "fields"=>"t4", "railing"=>"A-3", "wood"=>"wood_6
", "railing_m"=>"0", "order"=>"{\"sving\"=>\"right\", \"size\"=>{\"ground\"=>\"1
23\", \"floor\"=>\"6\", \"a\"=>\"6\", \"d\"=>\"6\"}, \"comments\"=>{\"step_2\"=>
\"\", \"step_3\"=>\"\", \"step_4\"=>\"\"}, \"railing\"=>{\"1\"=>\"1\", \"2\"=>\"
1\"}, \"railing_m\"=>{\"1\"=>\"\", \"2\"=>\"\", \"3\"=>\"\", \"4\"=>\"12\"}, \"h
ul\"=>{\"l\"=>\"123\", \"b\"=>\"123\"}, \"name\"=>\"qwed\", \"email\"=>\"mail#example.com\", \"phone\"=>\"13123\", \"street\"=>\"iuuj\", \"city\"=>\"ui\", \"postn
r\"=>\"213\"}"}
The problem is that all the nested http params are HTML escaped. How do I get rid of that?

The .post_form method accepts strings, so it causes this escaping problem when passed a nested hash. I had this same problem and switched to the .post method, and solved it.
require "net/http"
uri = URI('http://www.yoururl.com')
http = Net::HTTP.new(uri.host)
response = http.post(uri.path, params.to_query)
Note also the use of the .to_query method of converting a hash to a string. See here

In Rails world, params is not a regular Hash object that Ruby provides out of the box. In fact its a HashWithIndifferentAccess that is provided by Rails that allows the keys to be accessed, as a symbol or as a string.
irb(main):001:0>params = {"type"=>["raka"], "fields"=>["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0", "t2", "t3", "t4"], "railing"=>["A-3"], "wood"=>["wood_6"], "railing_m"=>"0", "order"=>{"sving"=>"right", "size"=>{"ground"=>"123", "floor"=>"6", "a"=>"6", "d"=>"6"}, "comments"=>{"step_2"=>"", "step_3"=>"", "step_4"=>""}, "railing"=>{"1"=>"1", "2"=>"1"}, "railing_m"=>{"1"=>"", "2"=>"", "3"=>"", "4"=>"12"}, "hul"=>{"l"=>"123", "b"=>"123"}, "name"=>"qwed", "email"=>"mail#example.com", "phone"=>"13123", "street"=>"iuuj", "city"=>"ui", "postnr"=>"213"}}
irb(main):002:0>params.class
=> Hash
irb(main):003:0>params[:fields]
=> nil
irb(main):004:0>params = params.with_indifferent_access
irb(main):005:0>params.class
=> ActiveSupport::HashWithIndifferentAccess
irb(main):006:0>params[:fields]
=> ["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0", "t2", "t3", "t4"]

Related

Rails 6 - Strong Parameters - allowing array

I am sending this simple hash as JSON to my controller:
{
"cars": [
{ "rego": "ABC123" }
]
}
In the controller, I am trying to allow the array of cars for further processing.
I tried the following:
params.permit(:cars)
params.permit(cars: [])
params.permit(:cars, cars: [])
In every attempt I am not getting anything in my filtered params:
DEBUG -- : Unpermitted parameters: :cars, :car, :user_username, :user_token
=> <ActionController::Parameters {} permitted: true>
I am using RoR 6.0.2.1 with Ruby 2.6.5.
Try params.permit(cars: [:rego])
params.permit(cars: []) allows cars as an array of primitive values
{
"cars": [1, 2, 3, 4]
}
"Strong Parameters" has more information.

Sending multiple string parameters to post request in Rails

I am using Net::HTTP::Post to send a request to a pre-determined url, like so:
my_url = '/path/to/static/url'
my_string_parameter = 'objectName=objectInfo'
my_other_string_parameter = 'otherObjectName=otherObjectInfo'
request = Net::HTTP::Post.new(my_url)
request.body = my_string_parameter
However, I know that my_url expects two string parameters. I have both parameters ready (they're statically generated) to be passed in. Is there a way to pass in multiple strings - both my_string_parameter as well as my_other_string_parameter to a post request via Ruby on Rails?
EDIT: for clarity's sake, I'm going to re-explain everything in a more organized fashion. Basically, what I have is
my_url = 'path/to/static/url'
# POST requests made to this url require 2 string parameters,
# required_1 and required_2
param1 = 'required_1=' + 'param1_value'
param2 = 'requred_2=' + 'param2_value'
request = request.NET::HTTP::Post.new(my_url)
If I try request.body = param1, then as expected I get an error saying "Required String parameter 'required_2' is not present". Same with request.body=param2, the same error pops up saying 'required_1' is not present. I'm wondering if there is a way to pass in BOTH parameters to request.body? Or something similar?
Try this.
uri = URI('http://www.example.com')
req = Net::HTTP::Post.new(uri)
req.set_form_data('param1' => 'data1', 'param2' => 'data2')
Alternative
uri = URI('http://www.example.com/')
res = Net::HTTP.post_form(uri, 'param1' => 'data1', 'param2' => 'data2')
puts res.body
For more request like Get or Patch you can refer This offical doc.
You can send it like this.
data = {'params' => ['parameter1', 'parameter2']}
request = Net::HTTP::Post.new(my_url)
request.set_form_data(data)
If your params are string:
url = '/path/to/controller_method'
my_string_parameter = 'objectName=objectInfo'
my_other_string_parameter = 'otherObjectName=otherObjectInfo'
url_with_params = "#{url}?#{[my_string_parameter, my_other_string_parameter].join('&')}"
request = Net::HTTP::Post.new(url_with_params)
If your params are hash It would be easier
your_params = {
'objectName' => 'objectInfo',
'otherObjectName' => 'otherObjectInfo'
}
url = '/path/to/controller_method'
url_with_params = "#{url}?#{your_params.to_query}"
request = Net::HTTP::Post.new(url_with_params)

Appending to a JSON Array in a loop

Need to submit an HTTP POST request of a json string.
Have all of the RESTful parts working, and verified correctly.
This works if I hard code the elements inside the array. I am wanting to loop through one of the arrays in the JSON string, the "Attachments Array".
The loop would look something like:
#days = Daily.all
#days[0..11] do |dailys|
#loop that builds json to post
end
#RESTful HTTP POST request
The only problem is, I don't know how to implement a loop inside of a JSON string for only one array.
My code so far for testing out the HTTP POST
#!/usr/bin/ruby
require 'net/http'
require 'uri'
require 'json'
require 'jbuilder'
uri = URI.parse("<POST URL>")
header = {'Content-Type' => 'text/json'}
payload = {
channel: "<channel>",
username: "<username>",
# Wish to loop through the "Attachments" Array
attachments: [
{
param: "Text",
text: "Text",
pretext: "Optional Text",
color: 'good',
fields: [
{
Title: "Title field",
value: "First Value",
short: false
},
{
title: "Field Title",
value: "Field Value",
short: true
},
{
title: "Second Field Title",
value: "Second Field Value",
short: true
}
]
}
]
}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri.request_uri, header)
req.body = payload.to_json
resp = http.request(req)
puts resp
Your code is looping through a bunch of Daily objects (though you're calling each one 'dailys' inside the loop which is confusing). You don't really explain what you want to do, but if you wanted to make a json object using some of the attributes of the Daily objects you have, you could do it like this.
hash = Daily.find(:all, :limit => 12).map{|daily| {:foo => daily.bar, :chunky => daily.chicken}}.to_json
If you give some details of the json string you want to make from your daily objects then i could give you some less silly code, but the approach is correct: build a ruby data structure then convert it to json with to_json
EDIT: following on from your comment, i would do this.
hash = Daily.find(:all, :limit => 12, :order => "id desc").map{|daily| {param: daily.title, fields: [{title: "Task Completed?", value: daily.completed, short: true}]} }
json = hash.to_json
Couple of notes:
1) Daily is a class, not an object (while classes are also objects in Ruby, i think that in rails it's better to refer to it as the class.
2) By the last 12 elements i assume you mean the most recently saved records: this is what the :order option is for.

Why is this Rails action returning a string instead of JSON?

I am accessing one of my Rails actions from the Rails console:
> #consumer = OAuth::Consumer.new(
> x,
> x,
> site: "http://localhost:3000"
> )
> request = #consumer.create_signed_request(:get,"/get_user_info?email=x")
> uri = URI.parse("http://localhost:3000")
> http = Net::HTTP.new(uri.host, uri.port)
> http.request(request).body
=> "{\"first_thing\":\"Nick\",\"second_thing\":\"2012-12-26T11:41:11Z\",\"third_thing\":\"2012-12-26T11:40:03Z\"}"
> http.request(request).body.class
=> String
The action is supposed to be returning a hash in JSON, not a string. Here is the how the action ends:
render json: {
first_thing: x,
second_thing: x,
third_thing: x
}
Why would this be coming through as a string? I'm using Rails 3.2.0 and Ruby 1.9.3.
You will always get a String from an HTTP request. render :json just converts the hash into a JSON String.
You need to do JSON.parse on the String.
It return JSON, because whole HTTP messages are string based. So to get JSON object in console you need call JSON.parse on response body.
JSON.parse(http.request(request).body) # => {
# first_thing: x,
# second_thing: x,
# third_thing: x
#}

Hash becomes array after post

I have a hash in Ruby:
params[:test]={:name=>'sharing'}
restPost(url, params)
on the other end, I output the params:
render :json=>{ :params=>params[:test] }
I get the result:
{"params":["name", "sharing"] }
It seems the hash is turned into a array. What I want is:
{"params": {"name":"sharing"}}
One way to deal with this might be to convert the array back to a Hash with Hash[], e.g.:
a = ["name", "sharing"]
h = Hash[*a]

Resources