i'm trying to learn simple stuff a make HTTP request to rails app.
the problem is, when i try to make HTTP post request to my rails app, code is :
uri = URI.parse("http://localhost:4000/posts")
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data( :post=> {"name" => "My query", "title" => "50"} )
response = http.request(request)
when i look into console for incoming post request, the output is:
Started POST "/posts" for 127.0.0.1 at 2015-02-02 16:14:12 +0100
Processing by PostsController#create as */*
Parameters: {"post"=>"{\"name\"=>\"My query\", \"title\"=>\"50\"}"}
Completed 500 Internal Server Error in 1ms
NoMethodError (undefined method `permit' for "{\"name\"=>\"My query\", \"title\"=>\"50\"}":String):
app/controllers/posts_controller.rb:72:in `post_params'
app/controllers/posts_controller.rb:27:in `create'
Look closely on parameters. Why does ist add additional quotation marks? how to fix this problem?
Because you are sending a stringified JSON object. I don't know what set_form_data is doing but you should be converting your request .to_json.
Look at this so question for reference here.
Related
I am fairly new to Ruby and Rails itself and I'm trying to build a simple Rails API.
I want to authenticate users via token and I am therefore using the devise_token_auth gem.
I can successfully make a POST request at /auth/sign_in and I am now trying to make a GET request at /auth/validate_token
What I have, as a "test":
uri = URI.parse("http://localhost:3000/auth/sign_in")
response = Net::HTTP.post_form(uri, {"email" => params[:session][:email], "password" => params[:session][:password]})
uri2 = URI.parse("http://localhost:3000/auth/validate_token")
params = { :auth_token => response['access-token'], :uid => response['uid'], :client => response['client'] }
uri2.query = URI.encode_www_form(params)
response2 = Net::HTTP.get_response(uri2)
I am therefore using the access-token and uid retrieved from the response header but I keep getting a 401 response code from /auth/validate_token:
Started GET "/auth/validate_token?auth_token=EEV40VDHfOaWtBzv3bn_DQ&uid=username%40example.com&client=NAzWNJalYBJLRni9dCGxXA" for ::1 at 2016-06-22 15:22:35 +0100
Processing by DeviseTokenAuth::TokenValidationsController#validate_token as */*
Parameters: {"auth_token"=>"EEV40VDHfOaWtBzv3bn_DQ", "uid"=>"username#example.com", "client"=>"NAzWNJalYBJLRni9dCGxXA"}
Completed 401 Unauthorized in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms)
What am I doing wrong? How can I solve this?
I believe the problem is twofold:
you send the authentication credentials as headers to the /validate_token endpoint
you send the token header as access-token instead of auth_token
You can read about it in this github issue. It may not have been at the time of your problem, but it is currently published in the README.
Here are all the headers necessary for a valid authenticated request (at the time of this writing):
"access-token": "wwwww",
"token-type": "Bearer",
"client": "xxxxx",
"expiry": "yyyyy",
"uid": "zzzzz"
Note: these are not necessary for every endpoint, but usually access-token, client, and uid are.
HTTParty
url = "https://my-url/locomotive/api/tokens.json"
response = HTTParty.post(url, body: { :api_key => #api_key })
On the server:
Started POST "/locomotive/api/tokens.json" for 202.4.224.66 at 2014-06-15 17:59:57 +1000
Processing by Locomotive::Api::TokensController#create as JSON
Parameters: {"api_key"=>"5fcfe580e42944c896a49469c30aa97a384b497d"}
$http
$http({
url: 'https://ernie-locomotive.12wbt.com/locomotive/api/tokens.json',
method: 'POST',
params: data
});
Started OPTIONS "/locomotive/api/tokens.json?api_key=5fcfe580e42944c896a49469c30aa97a384b497d" for 59.167.21.65 at 2014-06-15 17:53:43 +1000
Processing by Locomotive::Public::PagesController#show as JSON
Parameters: {"api_key"=>"5fcfe580e42944c896a49469c30aa97a384b497d", "path"=>"locomotive/api/tokens"}
WARNING: Can't verify CSRF token authenticity
Basically, I thought they are two same methods. Seems that $http doesn't pass http method. HTTParty does what it requers and grabs the results correctly.
Because it is cross origin request, browser sends CORS preflight request before actual one...
More about CORS: http://www.html5rocks.com/en/tutorials/cors/
I have a issue where I cant get my rails v4 app to recognize a JSON request. I am sending the following header('Content-Type' => 'application/json') from my mobile/client app and the request payload is a JSON string.
Started POST "/devices" for 127.0.0.1 at 2013-12-25 17:50:46 -0800
Processing by DevicesController#create as */*
respond_to do |format|
format.html
format.json do
# Request does not come in this block
end
end
However when I append ".json" to my request URL, my rails app is able to process it as a JSON request
Started POST "/devices.json" for 127.0.0.1 at 2013-12-25 17:13:43 -0800
Processing by DevicesController#create as JSON
Anything I am doing wrong?
So the Content-Type header describes request's type, not respose's.
Rails determines the desired response format from the HTTP Accept
header submitted by the client.
What you can do is check for request.content_type and render json: {} or HTML accordingly.
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.
I use devise 2.2.2 with rails 3.2.11
I use devise with ajax requests
I changed the following configuration in initializers/devise.rb
config.navigational_formats = [:json, :html]
config.http_authenticatable_on_xhr = false
when I submit an empty sign in request, I expect to get a json response with errors hash, but i get a 500 instead (see below for the trace) (it works fine with sign up request)
here are my routes (nothing special)
devise_for :users
the trace:
Started POST "/users/sign_in.json" for 127.0.0.1 at 2013-01-27 13:33:45 +0100
Processing by Devise::SessionsController#create as JSON
Parameters: {"user"=>{"email"=>"", "password"=>"[FILTERED]"}}
Completed 401 Unauthorized in 1ms
Processing by Devise::SessionsController#new as JSON
Parameters: {"user"=>{"email"=>"", "password"=>"[FILTERED]"}}
Completed 500 Internal Server Error in 40ms
NoMethodError (undefined method `users_url' for #<Devise::SessionsController:0x007fe88ddd9550>):
You are probably overriding after_sign_in_path_for and have a code path in there that returns nil.
This causes devise to fall back to its default behaviour and call users_url to get the path to redirect to.
Why do I think this? Because you are having the same error I had (and lost some hair over) and also this bug report contains the github usernames of many other people who have been humbled by this particular issue.