[英]Rails 4 - Respond only to JSON and not HTML
我正在嘗試在 rails 4 中構建 API,並且遇到了一個問題,即在使用respond_to :json
並嘗試訪問 html 版本時,rails 返回 500 錯誤而不是 406。
這是一個演示問題的示例控制器:
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
end
end
我還有一個用於index
的 jbuilder 視圖,該視圖在通過 JSON 訪問時有效。 如果我嘗試訪問沒有 JSON 擴展名的路由,它會嘗試加載 HTML 模板(不存在)並返回 500 錯誤,而不是僅呈現 JSON 或返回 406 錯誤。
什么可能導致這種情況? 為任何幫助干杯。
我相信這里有兩部分:
1) json 只在 rails 中請求
2) json 僅在 rails 中響應
1) 配置您的應用程序控制器以確保僅json 請求
# app/controller/application_controller.rb
before_action :ensure_json_request
def ensure_json_request
return if request.format == :json
render :nothing => true, :status => 406
end
2) 配置您的 Rails API 路由以確保僅json 響應
# config/routes.rb
MyApp::Application.routes.draw do
namespace :api, constraints: { format: 'json' } do
namespace :v1 do
resources :posts
end
end
end
為避免加載不存在的 HTML 模板,請在 config/routes.rb 中將默認資源類型設置為 JSON:
resources :posts, :defaults => { :format => :json }
在 Rails 4 中,您需要傳遞一個 lambda 來對路由實施約束。
不幸的是,這將不起作用,因為它仍然會嘗試提供(或嘗試提供)一個 html 模板,因為格式是一個可選參數:
resources :posts, constraints: { format: 'json' }
這確實有效(使用 lambda):
resources :posts, constraints: lambda { |req| req.format == :json }
請參閱Rails 指南本部分中的第二個(最后)注釋。
當您使用 before_filter 時,如果請求未定義的格式,您將收到 406 Not Acceptable。
例子:
class SomeController < ApplicationController
respond_to :json
def show
@record = Record.find params[:id]
respond_with @record
end
end
另一種方法是添加一個 before_filter 來檢查格式並做出相應的反應。
例子:
class ApplicationController < ActionController::Base
before_filter :check_format
def check_format
render :nothing => true, :status => 406 unless params[:format] == 'json'
end
end
但我認為,你可以這樣做:
respond_to do |format|
format.json { render :json => @posts }
end
更多信息: http : //guides.rubyonrails.org/layouts_and_rendering.html
constraints
不適用於 POST 請求,然后我嘗試了適用於所有人的defaults
。
namespace :api, :defaults => { :format => 'json' } do
namespace :v1 do
resources :users do
collection do
get 'profile'
end
end
post 'signup' => 'users#create'
post 'login' => 'user_sessions#create'
end
end
你可以試試這個,因為我也遇到了這個問題,現在使用這個解決方案解決了。
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
render json: @posts
end
end
您可以通過使用 before 過濾器將請求顯式設置為 JSON 來設置它。
request.format = :json
當您在 json 中嘗試響應時,因為您只需要一些我使用過的屬性
@my_model=Model.select(:attributeN, :attributeN......, attributeN)
respond_to do |format|
format.json {
render json: @my_model
}
end
我建議您嘗試gem 'active_model_serializers'
。 它真的很棒並且保持清潔。
應用控制器:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception, if: Proc.new { |c| c.request.format != 'application/json' }
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
end
路線:
namespace :api, defaults: { format: :json } do
resource :posts
end
帖子控制器:
def index
render json: Post.all
end
我對此有點晚了,但關於您對此答案的評論:
我希望所有響應都是 JSON
最簡單的解決方案是:
respond_to do |format|
format.all { render :json => @posts }
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.