Rails 4 - Отвечайте только на JSON, а не на HTML
Я пытаюсь создать API в rails 4, и у меня проблема, когда rails возвращает ошибку 500 вместо 406 при использовании respond_to :json
и пытается получить доступ к html-версии.
Вот пример контроллера, демонстрирующий проблему:
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
end
end
У меня также есть представление jbuilder для index
, которое работает при доступе через JSON. Если я попытаюсь получить доступ к маршруту без расширения JSON, он попытается загрузить HTML-шаблон (который не существует) и возвращает ошибку 500 вместо того, чтобы просто показывать JSON или возвращать ошибку 406.
Что может быть причиной этого? Приветствия за любую помощь.
Ответы
Ответ 1
Я считаю, что здесь есть две части:
1) json только запросы в рельсах
2) json только ответы в рельсах
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) Настройте маршруты API Rails, чтобы обеспечить ответы json
# config/routes.rb
MyApp::Application.routes.draw do
namespace :api, constraints: { format: 'json' } do
namespace :v1 do
resources :posts
end
end
end
Ответ 2
Чтобы избежать загрузки несуществующего шаблона HTML, задайте тип ресурса по умолчанию как JSON в config/routes.rb:
resources :posts, :defaults => { :format => :json }
Ответ 3
В Rails 4 вам нужно передать лямбду, чтобы принудительно использовать ограничение на маршруте.
К сожалению, это НЕ будет работать, потому что он все равно будет пытаться обслуживать (или пытаться обслуживать) шаблон html, поскольку формат является необязательным параметром:
resources :posts, constraints: { format: 'json' }
Эта работа работает (использует лямбда):
resources :posts, constraints: lambda { |req| req.format == :json }
Обратите внимание на вторую (окончательную) заметку в в этом разделе руководства Rails.
Ответ 4
Когда вы используете файл before_filter, у вас будет 406 недопустимый, если будет выполнен запрос для формата, который не определен.
Пример:
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
Ответ 5
Вы можете попробовать это, так как я тоже столкнулся с этой проблемой, и теперь он решается с помощью этого решения.
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
render json: @posts
end
end
Ответ 6
Вы можете установить его с помощью фильтра before, который явно задает запрос JSON.
request.format = :json
Ответ 7
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
Ответ 8
когда вы пытаетесь получить ответы в json, это просто, вам нужны только некоторые свойства, которые я использовал
@my_model=Model.select(:attributeN, :attributeN......, attributeN)
respond_to do |format|
format.json {
render json: @my_model
}
end
Ответ 9
Я предлагаю вам попробовать gem 'active_model_serializers'
. Это действительно потрясающе и сохраняет чистоту.
ApplicationController:
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