Ruby NoMethodError (undefined method `map') in Post Request - ruby

I'm trying to do a POST request from a ruby app and I'm getting the following error.
Here is the code:
def action_reply(token,action_id,reply_text)
require 'uri'
require 'net/http'
require 'net/https'
#reply = { 'ACTION_ID' => action_id, 'text' => reply_text }.to_json
#A token is required to do this post
#token_url = 'https://example.com/reply?oauth_token=' + token
uri = URI.parse(#token_url)
response = Net::HTTP.post_form(uri,#reply)
end
I'm getting an error in the last step that says:
NoMethodError (undefined method `map' for #<String:0x000000063798e8>)
Any idea why this is?
Thanks!

Because you're passing a string to a method expecting a hash: remove the to_json call.
Unrelated, but is it necessary to have those instance variables be instance variables?

Related

How to fix Ruby Rack SessionId error Error: undefined class/module Rack::Session::SessionId when decoding the rack.session cookie

While writing a ruby script to decode rack session cookies and load the object using the ruby function Marshal load, I am getting the following error:
Error: undefined class/module Rack::Session::SessionId
This is my ruby script:
require 'pp'
require 'base64'
require 'uri'
require 'rack' # solves the error: Error: undefined class/module Rack::
c = gets
cookie, signature = c.split("--")
decoded = Base64.decode64(URI.decode(cookie))
begin
object = Marshal.load(decoded)
pp object
rescue ArgumentError => e
puts "Error: " + e.to_s
end
How do I fix this? I tried looking for solutions on stackoverflow but couldn't figure it out.
Thanks to Louis Nyffenegger (#snyff) who helped me with this
https://twitter.com/snyff/status/1407054131697758211?s=20
This error can be solved by creating a method stub
require 'pp'
require 'base64'
require 'uri'
require 'rack'
class Rack::Session::SessionId
end
c = gets
cookie, signature = c.split("--")
decoded = Base64.decode64(URI.decode(cookie))
begin
object = Marshal.load(decoded)
pp object
rescue ArgumentError => e
puts "Error: " + e.to_s
end
Try clearing all of the cookies for the site.
I think this works because something is causing an exception while loading the Rack::Session::SessionId class.
This type of error happens occasionally when working on Rails applications. A SyntaxError (or any other exception) inside a class definition (e.g. in a model) can then cause an undefined class/module error instead of the real error.

Net::HTTP and Nokogiri - undefined method `body' for nil:NilClass (NoMethodError)

Thanks for your time. Somewhat new to OOP and Ruby and after synthesizing solutions from a few different stack overflow answers I've got myself turned around.
My goal is to write a script that parses a CSV of URLs using Nokogiri library. After trying and failing to use open-uri and the open-uri-redirections plugin to follow redirects, I settled on Net::HTTP and that got me moving...until I ran into URLs that have a 302 redirect specifically.
Here's the method I'm using to engage the URL:
require 'Nokogiri'
require 'Net/http'
require 'csv'
def fetch(uri_str, limit = 10)
# You should choose better exception.
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
url = URI.parse(uri_str)
#puts "The value of uri_str is: #{ uri_str}"
#puts "The value of URI.parse(uri_str) is #{ url }"
req = Net::HTTP::Get.new(url.path, { 'User-Agent' => 'Mozilla/5.0 (etc...)' })
# puts "THE URL IS #{url.scheme + ":" + url.host + url.path}" # just a reporter so I can see if it's mangled
response = Net::HTTP.start(url.host, url.port, :use_ssl => url.scheme == 'https') { |http| http.request(req) }
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
else
#puts "Problem clause!"
response.error!
end
end
Further down in my script I take an ARGV with the URL csv filename, do CSV.read, encode the URL to a string, then use Nokogiri::HTML.parse to turn it all into something I can use xpath selectors to examine and then write to an output CSV.
Works beautifully...so long as I encounter a 200 response, which unfortunately is not every website. When I run into a 302 I'm getting this:
C:/Ruby24-x64/lib/ruby/2.4.0/Net/http.rb:1570:in `addr_port': undefined method `+' for nil:NilClass (NoMethodError)
from C:/Ruby24-x64/lib/ruby/2.4.0/Net/http.rb:1503:in `begin_transport'
from C:/Ruby24-x64/lib/ruby/2.4.0/Net/http.rb:1442:in `transport_request'
from C:/Ruby24-x64/lib/ruby/2.4.0/Net/http.rb:1416:in `request'
from httpcsv.rb:14:in `block in fetch'
from C:/Ruby24-x64/lib/ruby/2.4.0/Net/http.rb:877:in `start'
from C:/Ruby24-x64/lib/ruby/2.4.0/Net/http.rb:608:in `start'
from httpcsv.rb:14:in `fetch'
from httpcsv.rb:17:in `fetch'
from httpcsv.rb:42:in `block in <main>'
from C:/Ruby24-x64/lib/ruby/2.4.0/csv.rb:866:in `each'
from C:/Ruby24-x64/lib/ruby/2.4.0/csv.rb:866:in `each'
from httpcsv.rb:38:in `<main>'
I know I'm missing something right in front of me but I can't tell what I should puts to see if it is nil. Any help is appreciated, thanks in advance.

Sinatra unit test - post with JSON body

I am trying to build a unit test for a REST API I built using Sinatra. For right now I just want to test that my echo function works right. Echo uses POST and will return the exact same payload from the post. I am still new with ruby, so forgive me if I don't use the proper lingo.
Here is the code I want to test:
post '/echo' do
request.body.read
end
This is the unit test I am trying to make:
ENV['RACK_ENV'] = 'test'
require './rest_server'
require 'test/unit'
require 'rack/test'
require 'json'
class RestServer < Test::Unit::TestCase
def app
Sinatra::Application
end
def test_check_methods
data = '{"dataIn": "hello"}'
response = post '/echo', JSON.parse(data)
assert.last_response.ok?
assert(response.body == data)
end
end
With the above code, here is the error:
NoMethodError: undefined method `dataIn' for Sinatra::Application:Class
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1285:in `block in compile!'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1285:in `each_pair'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1285:in `compile!'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1267:in `route'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1256:in `post'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1688:in `block (2 levels) in delegate'
/Users/barrywilliams/RubymineProjects/project/rest_server_test.rb:20:in `test_check_methods'
If I try doing it without the JSON.parse, I get
NoMethodError: undefined method `key?' for "{\"dataIn\": \"hello\"}":String
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1265:in `route'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1256:in `post'
/Users/barrywilliams/.rvm/gems/ruby-1.9.3-p448/gems/sinatra-1.3.4/lib/sinatra/base.rb:1688:in `block (2 levels) in delegate'
/Users/barrywilliams/RubymineProjects/project/rest_server_test.rb:20:in `test_check_methods'
If I try doing it where data = 'hello', then I get the same undefined method 'key?' error
I've tried this suggestion, with no success:
http://softwareblog.morlok.net/2010/12/18/testing-post-with-racktest/
I get an error saying that post only takes 2 arguments, not 3.
So, in summary, I need to be able to make a call, have the code I'm testing receive the call and return a response, then I need to be able to read that response and verify it was the original data. Right now it looks like it's getting stuck at just making the call.
I did a thing a little similar, it might help you :
The application post definition :
post '/' do
data = JSON.parse request.body.read.to_s
"Hello !\n#{data.to_s}"
end
The .to_s is necessary, else the conversions will not be exactly the same :-/
Then on the test file :
class RootPostTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Sinatra::Application
end
def test_return_the_parameters
data = {
'reqID' => 1,
'signedReqID' => "plop",
'cert' => "mycert"
}
post '/', data.to_json, "CONTENT_TYPE" => "application/json"
assert last_response.ok?
body_espected = "Hello !\n#{JSON.parse(data.to_json).to_s}"
assert_equal last_response.body, body_espected
end
end
Hope it helped you.
Rack Test will give you back the response body in last_response.body, no need to save it to a variable. You're also not echoing back what you've sent - data in the code you've given is JSON, but you converted it to a hash and posted that, so it's not going to match what comes back. Either send JSON, or convert it to JSON in the Sinatra route if you want to do that (see https://stackoverflow.com/a/12138793/335847 for more).
In the Sinatra app:
require 'json'
post '/echo' do
# Don't use request.body.read as you're not posting JSON
params.to_json
end
and in the test file:
def test_check_methods
data = '{"dataIn": "hello"}'
post '/echo', JSON.parse(data)
assert.last_response.ok?
assert(last_response.body == data)
end
If you do end up wanting to post JSON (which I think is usually not a good idea if it's easy to convert or already have the data as a hash) then use :provides => "json" as a condition to the route, and consider using Rack::Test::Accepts to make life easier writing the test for that (note: that's a shameless plug for a gem I wrote;)

Ruby namespacing issues

I'm attempting to build a gem for interacting w/ the Yahoo Placemaker API but I'm running into an issue. When I attempt to run the following code I get:
NameError: uninitialized constant Yahoo::Placemaker::Net
from /Users/Kyle/.rvm/gems/ruby-1.9.2-p290/gems/yahoo-placemaker-0.0.1/lib/yahoo-placemaker.rb:17:in `extract'
from (irb):4
from /Users/Kyle/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'
yahoo-placemaker.rb
require "yahoo-placemaker/version"
require 'json'
require 'ostruct'
require 'net/http'
module Yahoo
module Placemaker
def self.extract (text = '')
host = 'wherein.yahooapis.com'
payload = {
'documentContent' => text,
'appid' => APP_ID,
'outputType' => 'json',
'documentType' => 'text/plain'
}
req = Net::HTTP::Post.new('/v1/document')
req.body = to_url_params(payload)
response = Net::HTTP.new(host).start do |http|
http.request(req)
end
json = JSON.parse(response.body)
Yahoo::Placemaker::Result.new(json)
end
end
end
I have yet to figure out how exactly constant name resolution works in Ruby (I think the rules are a bit messy here), but from my experience it could well be that Net is looked up in the current namespace instead of the global one. Try using the fully qualified name:
::Net::HTTP::Post.new
A similar problem could occur in this line:
Yahoo::Placemaker::Result
You should replace it with either ::Yahoo::Placemaker::Result or better Result (as it lives in the current namespace).
Try requiring net/http before. Ruby is falling back to find it in the module if it isn't defined.
require 'net/http'

Convert to string/text ruby

I'm using the following code to download a page through a POST request:
require 'net/http'
require 'uri'
res = Net::HTTP.post_form(URI.parse('http://example.com'),{'post'=>'1'})
puts res.split("Date")
The URL I originally used has been replaced with example.com
It works great, but when I try to call split (last line) it returns an error:
<main>': undefined methodsplit' for # (NoMethodError)
I'm new to ruby, so I'm confused about this error.
The method you are calling returns a HTTPResponse object, so you need to leverage that object's methods to get what you want. maybe something like:
require 'net/http'
require 'uri'
res = Net::HTTP.post_form(URI.parse('http://example.com'),{'post'=>'1'})
puts res.body.split("Date")
Notice the body method.
Or, if you want to see all the data returned:
require 'net/http'
require 'uri'
res = Net::HTTP.post_form(URI.parse('http://example.com'),{'post'=>'1'})
puts res.inspect
Hope this helps!

Resources