轨道 3:respond_with和完成 406 不可接受



我正在为Rails应用程序构建一个API。我实际上有两个应用程序:服务器(API)和客户端(与API交互)。我正在尝试执行 post 请求以通过 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&amp;line=8&amp;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"=&gt;"Knife Party", "email"=&gt;"person@example.com", "phone_number"=&gt;"07949967627", "country"=&gt;"France", "city"=&gt;"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>#&lt;Api::V1::RequestsController:0x007f84c7688618&gt;</td></tr><tr><td>action_dispatch.backtrace_cleaner</td><td>#&lt;Rails::BacktraceCleaner:0x007f84c6f8d8e0&gt;</td></tr><tr><td>action_dispatch.cookies</td><td>#&lt;ActionDispatch::Cookies::CookieJar:0x007f84c7686de0&gt;</td></tr><tr><td>action_dispatch.logger</td><td>#&lt;ActiveSupport::TaggedLogging:0x007f84c6e51468&gt;</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"=&gt;{"artist_name"=&gt;"Knife Party", "email"=&gt;"person@example.com", "phone_number"=&gt;"07949967627", "country"=&gt;"France", "city"=&gt;"Paris"}, "action"=&gt;"create", "controller"=&gt;"api/v1/requests"}</td></tr><tr><td>action_dispatch.request.path_parameters</td><td>{:action=&gt;"create", :controller=&gt;"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"=&gt;{"artist_name"=&gt;"Knife Party", "email"=&gt;"person@example.com", "phone_number"=&gt;"07949967627", "country"=&gt;"France", "city"=&gt;"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>#&lt;ActionDispatch::Routing::RouteSet:0x007f84c6d6dc18&gt;</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>#&lt;Method: Thin::Connection#post_process&gt;</td></tr><tr><td>async.close</td><td>#&lt;EventMachine::DefaultDeferrable:0x007f84c68daf98&gt;</td></tr><tr><td>rack.errors</td><td>#&lt;IO:0x007f84c285a450&gt;</td></tr><tr><td>rack.input</td><td>#&lt;StringIO:0x007f84c7716a08&gt;</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"=&gt;{"artist_name"=&gt;"Knife Party", "email"=&gt;"person@example.com", "phone_number"=&gt;"07949967627", "country"=&gt;"France", "city"=&gt;"Paris"}}</td></tr><tr><td>rack.request.form_input</td><td>#&lt;StringIO:0x007f84c7716a08&gt;</td></tr><tr><td>rack.request.form_vars</td><td>request[artist_name]=Knife%20Party&amp;request[email]=person%40example.com&amp;request[phone_number]=07949967627&amp;request[country]=France&amp;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=&gt;"/", :domain=&gt;nil, :expire_after=&gt;nil, :secure=&gt;false, :httponly=&gt;true, :defer=&gt;false, :renew=&gt;false, :secret=&gt;"98d3f4e78a03eb75aa2bc26d3d26c10524c72dc70035198d8fc73d99aef3", :coder=&gt;#&lt;Rack::Session::Cookie::Base64::Marshal:0x007f84c75e6548&gt;, :id=&gt;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>&nbsp;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;amp;line=9&amp;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>&nbsp;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;amp;line=9&amp;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>&nbsp;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;amp;line=9&amp;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>&nbsp;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;amp;line=9&amp;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>nn          <script type="text/javascript">n            var Footnotes = function() {nn              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'));nn              }nn              function hideAllAndToggle(id) {n                hideAll();n                toggle(id)nn                location.href = '#footnotes_debug';n              }nn              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              }nn              function show(element) {n                element.style.display = 'block'n              }nn              function hide(element) {n                element.style.display = 'none'n              }nn              return {n                show: show,n                hide: hide,n                toggle: toggle,n                hideAllAndToggle: hideAllAndTogglen              }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 所建议的那样,我通过在请求 url 中添加.json来修改保存方法:

# ...
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&amp;line=9&amp;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

尝试使用respond_with设置位置

 @request =  Request.create(params[:request])
 respond_with(@request, :location => nil)

此外,您的客户端需要显示操作,这就是您遇到路由错误的原因

 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'

我也不明白你如何在客户端保存对象。.没有关于设置创建的 promary 密钥记录的逻辑。

似乎您的 api 在您期待 HTML 时只使用 json 响应。尝试更改此行:

self.class.post("/api/requests", { body: {

自:

self.class.post("/api/requests.json", { body: {

最新更新