I am building an API for a Rails app. I actually have two apps: a server (the API) and a client (interacting with the API). I am trying to do a post request to create a model object via an API call. When the object is valid, the model object is created but I get a Completed 406 Not Acceptable
error. The server throws the error silently, so a response object is returned. Enough writing/talking, here is some code:
Server API controller
class Api::V1::RequestsController < Api::V1::BaseController
respond_to :json
def create
respond_with Request.create!(params[:request])
end
end
Server routes
namespace :api do
scope module: :v1 do
resources :requests, only: [:index, :create]
end
end
Client controller
class RequestsController < ApplicationController
def new
@request = Request.new
end
def create
@request = Request.new(params[:request])
if response = @request.save
flash[:success] = "Request successfully sent"
p response
redirect_to request_url(@request)
else
render :new
end
end
end
Client model
class Request < ActiveRecord::Base
include HTTParty
if Rails.env.development?
base_uri "http://localhost:3000/"
end
def save
if self.valid?
self.class.post("/api/requests", { body: {
request: {
artist_name: self.artist_name,
email: self.email,
phone_number: self.phone_number,
country: self.country,
city: self.city
}
} })
else
false
end
end
end
Server logs
Started POST "/api/requests" for 127.0.0.1 at 2013-01-27 17:32:35 +0000
Processing by Api::V1::RequestsController#create as HTML
Parameters: {"request"=>{"artist_name"=>"Knife Party", "email"=>"[email protected]", "phone_number"=>"07949967627", "country"=>"France", "city"=>"Paris"}}
(0.4ms) BEGIN
Request Exists (0.4ms) SELECT 1 AS one FROM "requests" WHERE LOWER("requests"."email") = LOWER('[email protected]') LIMIT 1
SQL (1.0ms) INSERT INTO "requests" ("artist_name", "city", "country", "created_at", "email", "phone_number", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["artist_name", "Knife Party"], ["city", "Paris"], ["country", "France"], ["created_at", Sun, 27 Jan 2013 17:32:35 UTC +00:00], ["email", "[email protected]"], ["phone_number", "07949967627"], ["updated_at", Sun, 27 Jan 2013 17:32:35 UTC +00:00]]
(0.3ms) COMMIT
Completed 406 Not Acceptable in 27ms (ActiveRecord: 2.1ms)
Client logs (with the response object from the server)
#<HTTParty::Response:0x7f836dd944f8 parsed_response=" <!-- Footnotes Style -->\n <style type=\"text/css\">\n #footnotes_debug {font-size: 11px; font-weight: normal; margin: 2em 0 1em 0; text-align: center; color: #444; line-height: 16px;}\n #footnotes_debug th, #footnotes_debug td {color: #444; line-height: 18px;}\n #footnotes_debug a {color: #9b1b1b; font-weight: inherit; text-decoration: none; line-height: 18px;}\n #footnotes_debug table {text-align: center;}\n #footnotes_debug table td {padding: 0 5px;}\n #footnotes_debug tbody {text-align: left;}\n #footnotes_debug .name_values td {vertical-align: top;}\n #footnotes_debug legend {background-color: #fff;}\n #footnotes_debug fieldset {text-align: left; border: 1px dashed #aaa; padding: 0.5em 1em 1em 1em; margin: 1em 2em; color: #444; background-color: #FFF;}\n /* Aditional Stylesheets */\n \n </style>\n <!-- End Footnotes Style -->\n <!-- Footnotes -->\n <div style=\"clear:both\"></div>\n <div id=\"footnotes_debug\">\n Edit: <a href=\"txmt://open?url=file:///Users/aziz/Sandbox/ruby/rails/Azoui/warden/app/controllers/api/v1/requests_controller.rb&line=8&column=3\" onclick=\"\">Controller</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('partials_debug_info');return false;\">Partials (0)</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('stylesheets_debug_info');return false;\">Stylesheets (0)</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('javascripts_debug_info');return false;\">Javascripts (0)</a><br />Show: <a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('session_debug_info');return false;\">Session (0)</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('cookies_debug_info');return false;\">Cookies (0)</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('params_debug_info');return false;\">Params (3)</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('filters_debug_info');return false;\">Filters</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('routes_debug_info');return false;\">Routes</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('env_debug_info');return false;\">Env</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('queries_debug_info');return false;\"> <span style=\"background-color:#ffffff\">Queries (4)</span>\n <span style=\"background-color:#ffffff\">DB (2.011ms)</span>\n</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('log_debug_info');return false;\">Log (0)</a> | \n<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('general_debug_info');return false;\">General Debug</a><br />\n <fieldset id=\"partials_debug_info\" style=\"display: none\">\n <legend>Partials</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"stylesheets_debug_info\" style=\"display: none\">\n <legend>Stylesheets</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"javascripts_debug_info\" style=\"display: none\">\n <legend>Javascripts</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"session_debug_info\" style=\"display: none\">\n <legend>Session</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"cookies_debug_info\" style=\"display: none\">\n <legend>Cookies</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"params_debug_info\" style=\"display: none\">\n <legend>Params</legend>\n <div> <table class=\"name_value\" summary=\"Debug information for Params (3)\" >\n <thead><tr><th>Name</th><th>Value</th></tr></thead>\n <tbody><tr><td>:request</td><td>{\"artist_name\"=>\"Knife Party\", \"email\"=>\"[email protected]\", \"phone_number\"=>\"07949967627\", \"country\"=>\"France\", \"city\"=>\"Paris\"}</td></tr><tr><td>:action</td><td>\"create\"</td></tr><tr><td>:controller</td><td>\"api/v1/requests\"</td></tr></tbody>\n </table>\n</div>\n </fieldset>\n <fieldset id=\"filters_debug_info\" style=\"display: none\">\n <legend>Filter chain for Api::V1::RequestsController</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"routes_debug_info\" style=\"display: none\">\n <legend>Routes for Api::V1::RequestsController</legend>\n <div> <table summary=\"Debug information for Routes\" >\n <thead><tr><th>Path</th><th>Name</th><th>Options</th><th>Requirements</th></tr></thead>\n <tbody><tr><td>api_requests</td><td>request_method</td><td>{:action=>\"index\"}</td><td>{:request_method=>/^GET$/}</td></tr><tr><td></td><td>request_method</td><td>{:action=>\"create\"}</td><td>{:request_method=>/^POST$/}</td></tr></tbody>\n </table>\n</div>\n </fieldset>\n <fieldset id=\"env_debug_info\" style=\"display: none\">\n <legend>Env</legend>\n <div> <table >\n <thead><tr><th>Key</th><th>Value</th></tr></thead>\n <tbody><tr><td>CONTENT_LENGTH</td><td>148</td></tr><tr><td>CONTENT_TYPE</td><td>application/x-www-form-urlencoded</td></tr><tr><td>GATEWAY_INTERFACE</td><td>CGI/1.2</td></tr><tr><td>HTTP_CONNECTION</td><td>close</td></tr><tr><td>HTTP_HOST</td><td>localhost:3000</td></tr><tr><td>HTTP_VERSION</td><td>HTTP/1.1</td></tr><tr><td>ORIGINAL_FULLPATH</td><td>/api/requests</td></tr><tr><td>PATH_INFO</td><td>/api/requests</td></tr><tr><td>QUERY_STRING</td><td></td></tr><tr><td>REMOTE_ADDR</td><td>127.0.0.1</td></tr><tr><td>REQUEST_METHOD</td><td>POST</td></tr><tr><td>REQUEST_PATH</td><td>/api/requests</td></tr><tr><td>REQUEST_URI</td><td>/api/requests</td></tr><tr><td>SCRIPT_NAME</td><td></td></tr><tr><td>SERVER_NAME</td><td>localhost</td></tr><tr><td>SERVER_PORT</td><td>3000</td></tr><tr><td>SERVER_PROTOCOL</td><td>HTTP/1.1</td></tr><tr><td>SERVER_SOFTWARE</td><td>thin 1.5.0 codename Knife</td></tr><tr><td>action_controller.instance</td><td>#<Api::V1::RequestsController:0x007f84c7688618></td></tr><tr><td>action_dispatch.backtrace_cleaner</td><td>#<Rails::BacktraceCleaner:0x007f84c6f8d8e0></td></tr><tr><td>action_dispatch.cookies</td><td>#<ActionDispatch::Cookies::CookieJar:0x007f84c7686de0></td></tr><tr><td>action_dispatch.logger</td><td>#<ActiveSupport::TaggedLogging:0x007f84c6e51468></td></tr><tr><td>action_dispatch.parameter_filter</td><td>[:password]</td></tr><tr><td>action_dispatch.remote_ip</td><td>127.0.0.1</td></tr><tr><td>action_dispatch.request.content_type</td><td>application/x-www-form-urlencoded</td></tr><tr><td>action_dispatch.request.formats</td><td>[text/html]</td></tr><tr><td>action_dispatch.request.parameters</td><td>{\"request\"=>{\"artist_name\"=>\"Knife Party\", \"email\"=>\"[email protected]\", \"phone_number\"=>\"07949967627\", \"country\"=>\"France\", \"city\"=>\"Paris\"}, \"action\"=>\"create\", \"controller\"=>\"api/v1/requests\"}</td></tr><tr><td>action_dispatch.request.path_parameters</td><td>{:action=>\"create\", :controller=>\"api/v1/requests\"}</td></tr><tr><td>action_dispatch.request.query_parameters</td><td>{}</td></tr><tr><td>action_dispatch.request.request_parameters</td><td>{\"request\"=>{\"artist_name\"=>\"Knife Party\", \"email\"=>\"[email protected]\", \"phone_number\"=>\"07949967627\", \"country\"=>\"France\", \"city\"=>\"Paris\"}}</td></tr><tr><td>action_dispatch.request.unsigned_session_cookie</td><td>{}</td></tr><tr><td>action_dispatch.request_id</td><td>ca38df31ac3758fbed0753f83efe7bf8</td></tr><tr><td>action_dispatch.routes</td><td>#<ActionDispatch::Routing::RouteSet:0x007f84c6d6dc18></td></tr><tr><td>action_dispatch.secret_token</td><td>184d9143ce94750263caefe09316bcff11b84d5f32f51e6628665f2a7fe946828044aec5f5ce72780c6e3ccf85e26a2b50f306990968e1c44634cae42cc90f1d</td></tr><tr><td>action_dispatch.show_detailed_exceptions</td><td>true</td></tr><tr><td>action_dispatch.show_exceptions</td><td>true</td></tr><tr><td>async.callback</td><td>#<Method: Thin::Connection#post_process></td></tr><tr><td>async.close</td><td>#<EventMachine::DefaultDeferrable:0x007f84c68daf98></td></tr><tr><td>rack.errors</td><td>#<IO:0x007f84c285a450></td></tr><tr><td>rack.input</td><td>#<StringIO:0x007f84c7716a08></td></tr><tr><td>rack.multiprocess</td><td>false</td></tr><tr><td>rack.multithread</td><td>false</td></tr><tr><td>rack.request.cookie_hash</td><td>{}</td></tr><tr><td>rack.request.form_hash</td><td>{\"request\"=>{\"artist_name\"=>\"Knife Party\", \"email\"=>\"[email protected]\", \"phone_number\"=>\"07949967627\", \"country\"=>\"France\", \"city\"=>\"Paris\"}}</td></tr><tr><td>rack.request.form_input</td><td>#<StringIO:0x007f84c7716a08></td></tr><tr><td>rack.request.form_vars</td><td>request[artist_name]=Knife%20Party&request[email]=person%40example.com&request[phone_number]=07949967627&request[country]=France&request[city]=Paris</td></tr><tr><td>rack.request.query_hash</td><td>{}</td></tr><tr><td>rack.request.query_string</td><td></td></tr><tr><td>rack.run_once</td><td>false</td></tr><tr><td>rack.session</td><td>{}</td></tr><tr><td>rack.session.options</td><td>{:path=>\"/\", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :defer=>false, :renew=>false, :secret=>\"98d3f4e78a03eb75aa2bc26d3d26c10524c72dc70035198d8fc73d99aef3\", :coder=>#<Rack::Session::Cookie::Base64::Marshal:0x007f84c75e6548>, :id=>nil}</td></tr><tr><td>rack.url_scheme</td><td>http</td></tr><tr><td>rack.version</td><td>[1, 0]</td></tr></tbody>\n </table>\n</div>\n </fieldset>\n <fieldset id=\"queries_debug_info\" style=\"display: none\">\n <legend>Queries</legend>\n <div> <b id=\"qtitle_0\">UNKNOWN</b> (<a href=\"javascript:Footnotes.toggle('qtrace_0')\" style=\"color:#00A;\">trace</a>)<br />\n <span id=\"sql_0\">BEGIN</span><br />\n <span style='background-color:#ffffff'>SQL (0.000ms)</span> \n <p id=\"qtrace_0\" style=\"display:none;\"><a href=\"txmt://open?url=file:///Users/aziz/Sandbox/ruby/rails/Azoui/warden/app/controllers/api/v1/requests_controller.rb&amp;line=9&amp;column=1\">app/controllers/api/v1/requests_controller.rb:9:in `create'</a><br /></p><br />\n <b id=\"qtitle_1\">SELECT</b> (<a href=\"javascript:Footnotes.toggle('qtrace_1')\" style=\"color:#00A;\">trace</a>)<br />\n <span id=\"sql_1\">SELECT 1 AS one FROM \"requests\" WHERE LOWER(\"requests\".\"email\") = LOWER('[email protected]') LIMIT 1</span><br />\n <span style='background-color:#ffffff'>Request Exists (0.001ms)</span> \n <p id=\"qtrace_1\" style=\"display:none;\"><a href=\"txmt://open?url=file:///Users/aziz/Sandbox/ruby/rails/Azoui/warden/app/controllers/api/v1/requests_controller.rb&amp;line=9&amp;column=1\">app/controllers/api/v1/requests_controller.rb:9:in `create'</a><br /></p><br />\n <b id=\"qtitle_2\">INSERT</b> (<a href=\"javascript:Footnotes.toggle('qtrace_2')\" style=\"color:#00A;\">trace</a>)<br />\n <span id=\"sql_2\">INSERT INTO \"requests\" (\"artist_name\", \"city\", \"country\", \"created_at\", \"email\", \"phone_number\", \"updated_at\") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING \"id\"</span><br />\n <span style='background-color:#ffffff'>SQL (0.001ms)</span> \n <p id=\"qtrace_2\" style=\"display:none;\"><a href=\"txmt://open?url=file:///Users/aziz/Sandbox/ruby/rails/Azoui/warden/app/controllers/api/v1/requests_controller.rb&amp;line=9&amp;column=1\">app/controllers/api/v1/requests_controller.rb:9:in `create'</a><br /></p><br />\n <b id=\"qtitle_3\">UNKNOWN</b> (<a href=\"javascript:Footnotes.toggle('qtrace_3')\" style=\"color:#00A;\">trace</a>)<br />\n <span id=\"sql_3\">COMMIT</span><br />\n <span style='background-color:#ffffff'>SQL (0.000ms)</span> \n <p id=\"qtrace_3\" style=\"display:none;\"><a href=\"txmt://open?url=file:///Users/aziz/Sandbox/ruby/rails/Azoui/warden/app/controllers/api/v1/requests_controller.rb&amp;line=9&amp;column=1\">app/controllers/api/v1/requests_controller.rb:9:in `create'</a><br /></p><br />\n</div>\n </fieldset>\n <fieldset id=\"log_debug_info\" style=\"display: none\">\n <legend>Log</legend>\n <div></div>\n </fieldset>\n <fieldset id=\"general_debug_info\" style=\"display: none\">\n <legend>General (id=\"general_debug_info\")</legend>\n <div>You can use this tab to debug other parts of your application, for example Javascript.</div>\n </fieldset>\n\n <script type=\"text/javascript\">\n var Footnotes = function() {\n\n function hideAll(){\n Footnotes.hide(document.getElementById('partials_debug_info'));\nFootnotes.hide(document.getElementById('stylesheets_debug_info'));\nFootnotes.hide(document.getElementById('javascripts_debug_info'));\nFootnotes.hide(document.getElementById('session_debug_info'));\nFootnotes.hide(document.getElementById('cookies_debug_info'));\nFootnotes.hide(document.getElementById('params_debug_info'));\nFootnotes.hide(document.getElementById('filters_debug_info'));\nFootnotes.hide(document.getElementById('routes_debug_info'));\nFootnotes.hide(document.getElementById('env_debug_info'));\nFootnotes.hide(document.getElementById('queries_debug_info'));\nFootnotes.hide(document.getElementById('log_debug_info'));\nFootnotes.hide(document.getElementById('general_debug_info'));\n\n }\n\n function hideAllAndToggle(id) {\n hideAll();\n toggle(id)\n\n location.href = '#footnotes_debug';\n }\n\n function toggle(id){\n var el = document.getElementById(id);\n if (el.style.display == 'none') {\n Footnotes.show(el);\n } else {\n Footnotes.hide(el);\n }\n }\n\n function show(element) {\n element.style.display = 'block'\n }\n\n function hide(element) {\n element.style.display = 'none'\n }\n\n return {\n show: show,\n hide: hide,\n toggle: toggle,\n hideAllAndToggle: hideAllAndToggle\n }\n }();\n /* Additional Javascript */\n \n </script>\n </div>\n <!-- End Footnotes -->\n", @response=#<Net::HTTPNotAcceptable 406 Not Acceptable readbody=true>, @headers={"content-type"=>["text/html; charset=utf-8"], "x-ua-compatible"=>["IE=Edge"], "cache-control"=>["no-cache"], "x-request-id"=>["ca38df31ac3758fbed0753f83efe7bf8"], "x-runtime"=>["0.027491"], "connection"=>["close"], "server"=>["thin 1.5.0 codename Knife"]}>
Started POST "/requests" for 127.0.0.1 at 2013-01-27 17:34:07 +0000
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Eat6tObc84Oi+D4hjjoYZermjxi0+QVtEb9FRVJOxnU=", "request"=>{"artist_name"=>"Knife Party", "email"=>"[email protected]", "phone_number"=>"07949967627", "country"=>"France", "city"=>"Paris"}, "commit"=>"Send request"}
Completed 404 Not Found in 34ms
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"requests", :id=>#<Request artist_name: "Knife Party", email: "[email protected]", phone_number: "07949967627", country: "France", city: "Paris">}):
app/controllers/requests_controller.rb:20:in `create'
Rendered /Users/aziz/.rvm/gems/ruby-1.9.3-p327@portal/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.8ms)
Client gems used (and versions)
gem 'rails', '3.2.11'
gem 'httparty', '0.10.2'
Server gems used (and versions)
gem 'rails', '3.2.11'
Other Notes
When I use cURL to do a get request to get all model objects, it works perfectly. When I try to do a POST request with cURL...well it doesn't work because I am not using cURL properly and I don't know how to.
Update
As Vadim Chumel suggested, I modified the save method by adding .json
to the request url:
# ...
self.class.post("/api/requests.json", { body: {
# ...
Now I get a 500 error on the server (API side); here are the log of the request:
Started POST "/api/requests.json" for 127.0.0.1 at 2013-01-28 16:23:23 +0000
Processing by Api::V1::RequestsController#create as JSON
Parameters: {"request"=>{"artist_name"=>"Knife Party", "email"=>"[email protected]", "phone_number"=>"07949967627", "country"=>"France", "city"=>"Paris"}}
(0.2ms) BEGIN
Request Exists (1.0ms) SELECT 1 AS one FROM "requests" WHERE LOWER("requests"."email") = LOWER('[email protected]') LIMIT 1
SQL (1.1ms) INSERT INTO "requests" ("artist_name", "city", "country", "created_at", "email", "phone_number", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["artist_name", "Knife Party"], ["city", "Paris"], ["country", "France"], ["created_at", Mon, 28 Jan 2013 16:23:23 UTC +00:00], ["email", "[email protected]"], ["phone_number", "07949967627"], ["updated_at", Mon, 28 Jan 2013 16:23:23 UTC +00:00]]
(0.4ms) COMMIT
Completed 500 Internal Server Error in 14ms
NoMethodError (undefined method `request_url' for #<Api::V1::RequestsController:0x007f84c70d2660>):
<a href="txmt://open?url=file:///Users/aziz/Sandbox/ruby/rails/Azoui/warden/app/controllers/api/v1/requests_controller.rb&line=9&column=1">app/controllers/api/v1/requests_controller.rb:9:in `create'</a>
Rendered /Users/aziz/.rvm/gems/ruby-1.9.3-p327@warden/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered /Users/aziz/.rvm/gems/ruby-1.9.3-p327@warden/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)
Rendered /Users/aziz/.rvm/gems/ruby-1.9.3-p327@warden/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (14.1ms)
The weird thing is that in the whole server project, there isn't a mention of request_url
Try to setup location using respond_with
Also your client side needs show action, that's why you have routing error
Also I don't understand how you save object on client side.. There is no logic about setting created promary key record.