我正在为 Rails 应用程序构建 API。我实际上有两个应用程序:一个服务器(API)和一个客户端(与 API 交互)。我正在尝试通过 API 调用进行发布请求以创建模型对象。当对象有效时,会创建模型对象,但出现Completed 406 Not Acceptable
错误。服务器默默地抛出错误,因此返回一个响应对象。足够的写作/谈话,这里有一些代码:
服务器 API 控制器
class Api::V1::RequestsController < Api::V1::BaseController
respond_to :json
def create
respond_with Request.create!(params[:request])
end
end
服务器路由
namespace :api do
scope module: :v1 do
resources :requests, only: [:index, :create]
end
end
客户端控制器
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
客户模型
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
服务器日志
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"=>"admin@example.com", "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('admin@example.com') 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", "admin@example.com"], ["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)
客户端日志(带有来自服务器的响应对象)
#<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\"=>\"person@example.com\", \"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\"=>\"person@example.com\", \"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\"=>\"person@example.com\", \"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\"=>\"person@example.com\", \"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('person@example.com') 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"=>"person@example.com", "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: "person@example.com", 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)
使用的客户端 gem(和版本)
gem 'rails', '3.2.11'
gem 'httparty', '0.10.2'
使用的服务器 gem(和版本)
gem 'rails', '3.2.11'
其他注意事项
当我使用 cURL 执行 get 请求以获取所有模型对象时,它可以完美运行。当我尝试使用 cURL 发出 POST 请求时……它不起作用,因为我没有正确使用 cURL,而且我不知道该怎么做。
更新
正如 Vadim Chumel 所建议的,我通过添加.json
到请求 url 来修改保存方法:
# ...
self.class.post("/api/requests.json", { body: {
# ...
现在我在服务器(API 端)收到 500 错误;这是请求的日志:
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"=>"robert@example.com", "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('robert@example.com') 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", "robert@example.com"], ["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)
奇怪的是,在整个服务器项目中,并没有提到request_url