How to solve error with using NET::HTTP - ruby-on-rails

I want to post some data using standard ruby class NET::HTTP.
I have controller from examples
def request
require "net/http"
require "uri"
uri = URI.parse("http://google.com/")
# Shortcut
response = Net::HTTP.get_response(uri)
# Will print response.body
Net::HTTP.get_print(uri)
# Full
http = Net::HTTP.new(uri.host, uri.port)
response = http.request(Net::HTTP::Get.new(uri.request_uri))
end
My application gives error -
undefined method `content_mime_type' for #<Net::HTTPMovedPermanently 301 Moved Permanently readbody=true>
Why this is happening ?

Problem might be that in the last line of your code, there are two requests happening. The code translates to:
response = http.request(<result>) where the <some result> part is the return value from the call Net::HTTP::Get.new(uri.request_uri)
I think you were trying to do this instead:
http.request(uri.request_uri)

Related

Make http POST request that return xml response and parsing XML fields

I want to make a http POST request that parse XML response and return the value of SessionId field that is inside XML. This is what I tried so far.
Ps: is there a way I can run this class from the console, in the way that I can see the response?
class Documents::CreateSession
def initialize()
#username = Rails.secrets.legal_doc.username
#password= Rails.secrets.legal_doc.password
end
def start
require "net/http"
require "uri"
uri = URI.parse("http://example.com/search")
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"userid" => #username, "password" => #password})
response = http.request(request)
end
end
I think that you can run your code the way that you have it now. Start a console and do the following:
obj = Documents::CreateSession.new
obj.start
For debugging purposes, you could put a binding.pry in the start method before you make your request.

Running a HTTP request with rails

It has been a while since I have used Rails. I currently have a curl request as follows
curl -X GET -H 'Authorization: Element TOKEN, User TOKEN' 'https://api.cloud-elements.com/elements/api-v2/hubs/marketing/ping'
All I am looking to do is to be able to run this request from inside of a rails controller, but my lack of understanding when it comes to HTTP requests is preventing me from figuring it out to how best handle this. Thanks in advance.
Use this method for HTTP requests:
def api_request(type , url, body=nil, header =nil )
require "net/http"
uri = URI.parse(url)
case type
when :post
request = Net::HTTP::Post.new(uri)
request.body = body
when :get
request = Net::HTTP::Get.new(uri)
when :put
request = Net::HTTP::Put.new(uri)
request.body = body
when :delete
request = Net::HTTP::Delete.new(uri)
end
request.initialize_http_header(header)
#request.content_type = 'application/json'
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') {|http| http.request request}
end
Your example will be:
api_request(:get, "https://api.cloud-elements.com/elements/api-v2/hubs/marketing/ping",nil, {"Authorization" => "Element TOKEN, User TOKEN" })
It would be something like the following. Note that the connection will be blocking, so it can tie up your server depending on how quickly the remote host returns the HTTP response and how many of these requests you are making.
require 'net/http'
# Let Ruby form a canonical URI from our URL
ping_uri = URI('https://api.cloud-elements.com/elements/api-v2/hubs/marketing/ping')
# Pass the basic configuration to Net::HTTP
# Note, this is not asynchronous. Ruby will wait until the HTTP connection
# has closed before moving forward
Net::HTTP.start(ping_uri.host, ping_uri.port, :use_ssl => true) do |http|
# Build the request using the URI as a Net::HTTP::Get object
request = Net::HTTP::Get.new(ping_uri)
# Add the Authorization header
request['Authorization'] = "Element #{ELEMENT_TOKEN}, User #{user.token}"
# Actually send the request
response = http.request(request)
# Ruby will automatically close the connection once we exit the block
end
Once the block exits, you can use the response object as necessary. The response object is always a subclass (or subclass of a subclass) of Net::HTTPResponse and you can use response.is_a? Net::HTTPSuccess to check for a 2xx response. The actual body of the response will be in response.body as a String.

Why Rails (current 4.0) fails to interpret nested JSON (from a HTTP POST)?

I am writing a simple client server application (using only JSON API) with Ruby (client) and Rails (server).
When trying to create a game from client, I am using:
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"tttgame" => {"name" => "Marius"}})
resp = http.request(request)
On server side (tttgames_controller.rb) I have:
# POST /tttgames
# POST /tttgames.json
def create
#tttgame = Tttgame.new(tttgame_params)
...
end
...
def tttgame_params
params.require(:tttgame).permit(:name)
end
Logs on server are:
Started POST "/tttgames.json" for 127.0.0.1 at 2013-10-05 12:58:44 +0300
Processing by TttgamesController#create as JSON
Parameters: {"tttgame"=>"{\"name\"=>\"Marius\"}"}
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `stringify_keys' for "{\"name\"=>\"Marius\"}":String):
app/controllers/tttgames_controller.rb:33:in `create'
How can I fix this? All examples from the Internet are looking the same. Thanks!
Both methods set_form_data and post_form are encoding data using format x-www-form-urlencoded. Check here.
Examples that are provided do not contain nested hashes.
I have found here an example, under the REST methods section, which works very well.
Thus, in order to get on server a valid structure with nested hashes, the client should use square brackets:
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"tttgame[name]" => “Marius”)
resp = http.request(request)
or much simpler:
uri = URI.parse(url)
resp = Net::HTTP.post_form(uri, {"tttgame[name]" => “Marius”})
This will generate on server
Parameters: {"tttgame"=>{"name"=>"Marius"}}
You might want to do this instead. It's even more compact.
uri = URI.parse(url)
resp = Net::HTTP.post_form(uri, "tttgame" => {"name" => "Marius"})
From http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#label-POST+with+Multiple+Values
UPDATE: In addition, your String is not a valid JSON. It needs to be "{\"name\":\"Marius\"}" instead.
You need to parse that response, because right now it is a String ("{\"name\"=>\"Marius\"}") but you actually need a Hash ({"name" => "Marius"}).
Therefore #stringify_keys fails because it is a method that operates on a Hash.
So do a:
#tttgame = Tttgame.new(JSON.parse(tttgame_params))
instead. This will turn your serialized JSON response into a Hash from a String.

How do I touch a URL with rails?

I have a json URL supplied by sendgrid. All it needs to be is touched. How would I do this?
def suspend
#user = User.find(params[:id])
#user.update_attribute("suspended", true)
# the url I need to touch => https://sendgrid.com/api/unsubscribes.add.xml?api_user=username%40website.com&api_key=secret_password&email=#{#user.email}
end
You can use Net::HTTP.get from standard library (see docs):
require 'net/http'
Net::HTTP.get URI("https://sendgrid.com/api/unsubscribes.add.xml?api_user=username%40website.com&api_key=secret_password&email=#{#user.email}")
Updated:
For HTTPS you can do smth like that:
require "net/https"
uri = URI.parse("https://www.google.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
# request = Net::HTTP::Head.new(uri.request_uri) - get response without body
response = http.request(request)
Nice article on the subject - Ruby Net::HTTP Cheat Sheet.
Install httpclient gem
HTTPClient.get("https://sendgrid.com/api/unsubscribes.add.xml?api_user=username%40website.com&api_key=secret_password&email=#{#user.email}")
maybe try ActionDispatch GET http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-GET
require 'open-uri'
open("http://pragprog.com/") { |f| f.gets }
result? just one row, not the whole page:
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"

Net::HTTP::Put.new(url.path) shows the 401 error in RUby

HI ,
i am new to ROR
i am writing Ruby code for calling API blogs
i have written ruby code for
Creating the blog by
require 'net/http'
require 'uri'
url = URI.parse('http://localhost:3000/api/blogs/create.xml')
req = Net::HTTP::Post.new(url.path)
req.basic_auth 'a', 'a'
req.set_form_data({'blogpost[title]'=>'TestingAPIBlogposttitle',
'blogpost[description]'=>'Testing api desc',
'blogpost[category_id]'=>'3121'}, ';')
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req)}
case res
when Net::HTTPSuccess, Net::HTTPRedirection
puts res.body
else
res.error!
end
which runs successfully by creating a new blog
And i have a search code
require 'net/http'
require 'uri'
require 'cgi'
## Change this part according to the api to be accessed and the params to be passed.
uri = URI.parse( "http://localhost:3000/api/blogs/show/blogtitle.xml" )
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.path)
request.basic_auth 'a', 'a'
response = http.request(request)
puts response.body
which returns the
<?xml version="1.0" encoding="UTF-8"?>
<blogpost>
<created-at type="datetime">2010-09-02T08:18:22Z</created-at>
<description><p>Blog desc</p></description>
<slug>blogtitle</slug>
<title>blogtitle</title>
<user>
<firstname>admin</firstname>
<lastname>k</lastname>
<login>admin</login>
</user>
</blogpost>
Now i am trying to Update a BLog
for this how to write the code
i tried by simply changing the POST.new by PUT.new
but it didnt works for me
its showing me the error even if i gave admin User credentials
It might be worth trying a POST request but also adding a _method = 'put' parameter to the request. Rails can simulate a PUT request in this way though I would expect it to respond correctly to an HTTP PUT too.

Resources