Вот решение, к которому я пришел, чтобы оно заработало.
- Создайте спецификацию контроллера в
spec/controller/fake_controller_spec.rb
следующим образом:
require 'rails_helper'
class FakeController < ApplicationController
def render(*args)
args.first
end
end
RSpec.describe FakeController, type: :controller do
it_should_behave_like "JSON Responsive controller", FakeController
end
Мне пришлосьпереопределить render(*args)
метод для возможности вызова render
изнутри Response
модуля озабоченности.
Создайте спецификацию shared_examples в
spec/shared/json_response.rb
:
require 'rails_helper'
RSpec.shared_examples 'JSON Responsive controller' do |including_controller|
let(:instance) { including_controller.new }
it 'should respond to #json_response' do
expect(instance).to respond_to(:json_response)
end
it 'should respond #respond_with_errors' do
expect(instance).to respond_to(:respond_with_errors)
end
it 'should respond to #paginated_response_status' do
expect(instance).to respond_to(:paginated_response_status)
end
context '#paginated_response_status' do
it 'returns 200 if collection is not paginated' do
expect(instance.paginated_response_status([1])).to eq :ok
end
it 'returns 206 if collection is paginated' do
collection = (1..35).to_a
expect(instance.paginated_response_status(collection)).to eq :partial_content
end
end
context '#respond_with_errors' do
it 'returns :unprocessable_entity status' do
model = double(:model)
errors = double(:errors, messages: {})
allow(model).to receive(:errors).and_return(errors)
response = instance.respond_with_errors(model)
expect(response[:status]).to eq :unprocessable_entity
end
end
context '#json_response' do
it 'returns JSON with default :ok status' do
model = double(:model)
response = instance.json_response(model)
expect(response[:status]).to eq :ok
end
it 'returns JSON with the specified status' do
model = double(:model)
response = instance.json_response(model, :partial_content)
expect(response[:status]).to eq :partial_content
end
end
end
Обратите внимание: чтобы иметь возможность использовать общий пример, определенный в папке shared
, необходимо добавить следующее к rails_helper.rb
файл:
Dir[Rails.root.join('spec/shared/**/*.rb')].each { |f| require f }
...
RSpec.configure do |config|
..
end
Наконец, вот код для проверки, определенный в
controllers/concerns/response.rb
:
module Response
extend ActiveSupport::Concern
def json_response(object, status = :ok, opts = {})
response = {json: object, status: status}.merge(opts)
render response
end
def respond_with_errors(object)
render json: { errors: ErrorSerializer.serialize(object) }, status: :unprocessable_entity
end
def paginated_response_status(collection)
collection.size > WillPaginate.per_page ? :partial_content : :ok
end
end
ErrorSerializer
- это просто еще один модуль, который создает JSON для возврата в случае ошибок:
#controllers/concerns/error_serializer.rb
module ErrorSerializer
extend ActiveSupport::Concern
def self.serialize(object)
object.errors.messages.map do |field, errors|
errors.map do |error_message|
{
status: 422,
title: 'Invalid attribute',
source: { pointer: "/data/attributes/#{field}" },
detail: error_message
}
end
end.flatten
end
end
Надеюсь, это поможет.