Настройка заголовка Content-Type для RSpec и Rails-API

Я использую rails-api gem для создания веб-службы и хочу протестировать мой API с помощью RSpec. Каждый запрос, который я делаю, независимо от метода HTTP, имеет заголовок CONTENT_TYPE, заданный как "application/x-www-form-urlencoded". Это не проблема, пока я не попытаюсь использовать wrap_parameters в моем контроллере, и это не влияет на хеш params:

class ApplicationController < ActionController::API
  include ActionController::ParamsWrapper
end

class ProjectsController < ApplicationController
  wrap_parameters :project, include: [:name]
  # ...
end

Этот хак больше не работает (@request is nil), и ни один из других сообщений, которые я нашел, тоже работает.

Если я сделаю следующий запрос в моем тесте RSpec:

put "/projects/1.json", {name: 'Updated Project 1'}

и поставьте отладчик в мой контроллер, я получаю:

(rdb:1) p params
    { "name"=>"Updated Project 1",
  "action"=>"update",
  "controller"=>"projects",
  "id"=>"5539bbd9-010c-4cfb-88d3-82dadbc99507",
  "format"=>"json"
}

(rdb:1) p request.content_type
"application/x-www-form-urlencoded"

Я ожидаю увидеть что-то подобное для хэша params (обратите внимание на добавление ключа проекта):

{ "name"=>"Updated Project 1",
  "action"=>"update",
  "controller"=>"projects",
  "id"=>"5539bbd9-010c-4cfb-88d3-82dadbc99507",
  "format"=>"json",
  "project" => {"name" => "Updated Project 1"}
}

Можно ли установить заголовок типа контента, используя только RSpec? Или мне нужно использовать стойку/тест для этой функции?

Ответ 1

Много разочарований и вариаций, и то, что сработало для меня. Rails 3.2.12 Rspec 2.10

 @request.env["HTTP_ACCEPT"] = "application/json"
 @request.env["CONTENT_TYPE"] = "application/json"
 put :update, :id => 1, "email" => "[email protected]"

wrap_parameters, похоже, работает таким образом

wrap_parameters User, format: :json

используется для User model

Ответ 2

Это работало для меня Rails 4.0.3 и Rspec 2.14.1, если кто-то ищет более свежие версии.

put '/projects/1.json', {name: 'Updated Project 1'}, {
  'HTTP_ACCEPT' => 'application/json',
  'CONTENT_TYPE' => 'application/json'
}

и

wrap_parameters Project, format: :json

Ответ 3

Используя новые настройки Rails v5.0.x API, я обнаружил, что эта проблема с rails по умолчанию для всех до "application/x-www-form-urlencoded" все еще остается проблемой для тестирования с запросами RSpec-Rails

Вот что я сделал, чтобы исправить проблему:

Создайте файл поддержки в ./spec/support/json_requests.rb

Отредактируйте это как нечто подобное, чтобы переопределить поведение для всех ваших API только JSON-запросов:

module JsonRequests
  def get(*args)
    super(*json_args(*args))
  end

  def post(*args)
    super(*json_args(*args))
  end

  def update(*args)
    super(*json_args(*args))
  end

  def patch(*args)
    super(*json_args(*args))
  end

  def put(*args)
    super(*json_args(*args))
  end

  def delete(*args)
    super(*json_args(*args))
  end

  def json_args(path, params = {}, headers = {})
    [path, params.to_json, headers.merge('CONTENT_TYPE' => 'application/json')]
  end
end

RSpec.configure do |config|
  config.include JsonRequests, type: :request
end

Имейте в виду, что это переопределит все спецификации в ./spec/requests, поэтому, если вам нужно использовать "application/x-www-form-urlencoded", вы также можете include этот модуль вручную по мере необходимости в вашем блоке Describe 'something' do.

Ответ 4

Если вы используете Rails 4 (и rspec ~ 3.7) и не хотите использовать встроенный синтаксис:

request.headers["CONTENT_TYPE"] = "application/json"

Ответ 5

Рельсы 5 без хаков:

put(:update,
    params: {project_id: 1},
    body: {name: 'Updated Project 1'}.to_json,
    as: :json)

Это правильно устанавливает content_type. В контроллере params будет храниться как params, так и body.