Rails 4 + Rails-API + RSpec + Devise — тестирование контроллеров с пользовательскими маршрутами разработки

В настоящее время я создаю API и пытаюсь протестировать свой контроллер. Я получаю сообщения об ошибках, связанных с Devise, которые я не могу решить. Вот что у меня есть на данный момент:

# /spec/requests/api/v1/sessions_spec.rb
require 'spec_helper'

describe API::V1::SessionsController do
  describe "POST /sessions" do
    it "on success, returns the user's authentication token" do
      user = FactoryGirl.create(:user)

      user_params = {
        "user" => {
          "email" => user.email,
          "password" => user.password
        }
      }.to_json

      post "/api/v1/sessions", user_params

      expect(response.status).to eq(200)
      json = JSON.parse(response.body)
      expect(json['authentication_token']).to eq(user.authentication_token)
    end
  end
end


# /app/controllers/api/v1/sessions_controller.rb
class API::V1::SessionsController < Devise::SessionsController
  respond_to :json

  def create
  end
end


# routes.rb
MyApplication::Application.routes.draw do
  namespace :api, defaults: { format: :json } do
    namespace :v1 do
      devise_scope :user do
        post 'sessions' => 'sessions#create', :as => 'login'
      end
    end
  end
end

Ошибка, которую я сейчас получаю:

1) API::V1::SessionsController POST /sessions on success, returns the user's authentication token
 Failure/Error: post "/api/v1/sessions", user_params
 AbstractController::ActionNotFound:
   Could not find devise mapping for path "/api/v1/sessions".
   This may happen for two reasons:

   1) You forgot to wrap your route inside the scope block. For example:

     devise_scope :user do
       get "/some/route" => "some_devise_controller"
     end

   2) You are testing a Devise controller bypassing the router.
      If so, you can explicitly tell Devise which mapping to use:

      @request.env["devise.mapping"] = Devise.mappings[:user]
 # ./spec/requests/api/v1/sessions_spec.rb:21:in `block (3 levels) in <top (required)>'

Я искал решение этой проблемы и пробовал кучу разных вопросов. Решение вопроса здесь (Как писать тесты контроллера когда вы переопределяете контроллер регистрации разработки?) сказали поместить приведенный ниже код в блок before в спецификации.

before :each do
  request.env['devise.mapping'] = Devise.mappings[:user]
end

Но когда я добавляю это в свой контроллер, я получаю другую ошибку, которая говорит:

1) API::V1::SessionsController POST /sessions on success, returns the user's     authentication token
 Failure/Error: request.env['devise.mapping'] = Devise.mappings[:user]
 NoMethodError:
   undefined method `env' for nil:NilClass
 # ./spec/requests/api/v1/sessions_spec.rb:7:in `block (2 levels) in <top (required)>'

Решение другого вопроса здесь (неопределенный метод 'env' для nil:NilClass) говорит попробовать добавляя include Devise::TestHelpers в спецификацию, но когда я это делаю, возвращается та же ошибка.

Текущие драгоценные камни, которые я использую:

рельсы (4.0.2)

рельсы API (0.2.0)

rspec-рельсы (2.14.1)

разработать (3.2.2)

Используйте эти два руководства в качестве руководства: https://lucatironi.github.io/tutorial/2012/10/15/ruby_rails_android_app_authentication_devise_tutorial_part_one/

http://commandercoriander.net/blog/2014/01/04/test-driving-a-json-api-in-rails/

Любая помощь будет оценена, спасибо!


person Alex E    schedule 21.04.2014    source источник


Ответы (2)


Я думаю, что, возможно, решил проблему. Кажется, мне пришлось добавить devise_for вне блоков пространства имен API:

MyApplication::Application.routes.draw do

  devise_for :users, skip: [:sessions, :passwords, :registrations]

  namespace :api, defaults: { format: :json } do
    namespace :v1 do
      devise_scope :user do
        post 'sessions' => 'sessions#create', :as => 'login'
      end
    end
  end
end

Я оставлю вопрос открытым немного дольше на случай, если при тестировании возникнут какие-либо другие проблемы.

person Alex E    schedule 21.04.2014

Заменять

  request.env['devise.mapping'] = Devise.mappings[:user]

С участием

  @request.env['devise.mapping'] = Devise.mappings[:user]

Обратите внимание, что в сообщении об ошибке конкретно предлагается использовать:

 2) You are testing a Devise controller bypassing the router.
      If so, you can explicitly tell Devise which mapping to use:

      @request.env["devise.mapping"] = Devise.mappings[:user]
person Kirti Thorat    schedule 21.04.2014
comment
К сожалению, я получаю ту же ошибку с или без @ перед запросом - person Alex E; 22.04.2014
comment
Можете ли вы поделиться конкретными маршрутами вашего устройства из файла routes.rb. Пожалуйста, обновите в вопросе. - person Kirti Thorat; 22.04.2014
comment
Это уже есть в вопросе, прокрутите вниз в первом поле кода. - person Alex E; 22.04.2014