Подтвердить что ты не робот

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.

Что может быть причиной этого? Приветствия за любую помощь.

4b9b3361

Ответ 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