[英]Why does Rails RSpec response show 302 instead of 401?
I have been stuck on this problem for several days and I don't know what is wrong with it.我已经被这个问题困扰了好几天了,我不知道它有什么问题。 I started Ruby on Rails few months ago and I am currently learning authentication with API.
几个月前我开始使用 Ruby on Rails,目前正在学习使用 API 进行身份验证。 I have looked at other similar topics here and there but none of them helped.
我在这里和那里查看了其他类似的主题,但没有一个有帮助。
My problem is whenever I run RSpec on this code (located at spec/api/v1/controllers/posts_controller_spec.rb
)我的问题是每当我在此代码上运行 RSpec(位于
spec/api/v1/controllers/posts_controller_spec.rb
)
require 'rails_helper'
RSpec.describe Api::V1::PostsController, type: :controller do
let(:my_user) { create(:user) }
let(:my_topic) { create(:topic) }
let(:my_post) { create(:post, topic: my_topic, user: my_user) }
context "unauthenticated user" do
it "PUT update returns http unauthenticated" do
put :update, topic_id: my_topic.id, id: my_post.id, post: {title: my_post.title, body: my_post.body}
expect(response).to have_http_status(401)
end
...
I keep getting我不断得到
...
spec/api/v1/controllers/posts_controller_spec.rb -e "unauthenticated user"
Run options: include {:full_description=>/unauthenticated\ user/}
FFF
Failures:
1) PostsController unauthenticated user PUT update returns http unauthenticated
Failure/Error: expect(response).to have_http_status(401)
expected the response to have status code 401 but it was 302
# ./spec/api/v1/controllers/posts_controller_spec.rb:12:in `block (3 levels) in <top (required)>'
If this helps, my controller, app/controllers/api/v1/posts_controller_spec.rb
has如果这有帮助,我的控制器
app/controllers/api/v1/posts_controller_spec.rb
有
class Api::V1::PostsController < Api::V1::BaseController
before_action :authenticate_user, except: [:index, :show]
before_action :authorize_user, except: [:index, :show]
def update
post = Post.find(params[:id])
if post.update_attributes(post_params)
render json: post.to_json, status: 200
else
render json: {error: "Post update failed", status: 400}, status: 400
end
end
...
My base_controller我的 base_controller
class Api::V1::BaseController < ApplicationController
skip_before_action :verify_authenticity_token
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActionController::ParameterMissing, with: :malformed_request
def authenticate_user
authenticate_or_request_with_http_token do |token, options|
@current_user = User.find_by(auth_token: token)
end
end
def authorize_user
unless @current_user && @current_user.admin?
render json: {error: "Not Authorized", status: 403}, status: 403
end
end
def malformed_request
render json: {error: "The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.", status: 400}, status: 400
end
def not_found
render json: {error: "Record not found", status: 404}, status: 404
end
end
Lastly, routes.rb shows:最后, routes.rb 显示:
namespace :api do
namespace :v1 do
resources :users, only: [:index, :show, :create, :update]
resources :topics, except: [:edit, :new] do
resources :posts, only: [:update, :create, :destroy]
end
end
end
I have a strong hunch that my before_action is the culprit, but I can't pinpoint what I did wrong.我有一种强烈的预感,我的 before_action 是罪魁祸首,但我无法确定我做错了什么。 I have done similar thing on Topics (Posts are nested within Topics) using similar RSpec testing and my Topic RSpec passes, whereas my Posts RSpec fail miserably.
我使用类似的 RSpec 测试在主题(帖子嵌套在主题中)上做了类似的事情,并且我的主题 RSpec 通过,而我的帖子 RSpec 失败了。
Can someone please help me to point out what I did wrong, and how can I pass the RSpec test and not show 302 status code?有人可以帮我指出我做错了什么,我怎样才能通过 RSpec 测试而不显示 302 状态码?
As an extra, why did it show 302 status code?另外,为什么显示302状态码?
The problem is that you're using问题是你正在使用
before_action :authenticate_user, except: [:index, :show]
, probably the helper from Devise, correct? before_action :authenticate_user, except: [:index, :show]
,可能是 Devise 的助手,对吗? If so, when you try to access a resource without being logged in, this helper will redirect you to the login page, something that you expect to happen when you're using a browser, which is not your case.如果是这样,当您尝试在未登录的情况下访问资源时,此帮助程序会将您重定向到登录页面,这是您在使用浏览器时期望发生的事情,而您的情况并非如此。 You can find some alternatives, overwriting the Devise behavior, my solution was to define my
authenticate_user!
您可以找到一些替代方案,覆盖设计行为,我的解决方案是定义我的
authenticate_user!
method to return a 401 if the user was not signed in, using another devise helper method, something like this:如果用户未登录,则返回 401 的方法,使用另一个设计辅助方法,如下所示:
def authenticate_user!
if user_signed_in?
@user = current_user
else
head :unauthorized
end
end
This is just the case that worked for me, yours may be different.这只是对我有用的情况,你的可能会有所不同。
I ran into to same issue, while normally using我遇到了同样的问题,而通常使用
let(:auth_headers) { Devise::JWT::TestHelpers.auth_headers({ 'ACCEPT': 'application/json' }, user) }
# ...
get "/api/v1/something", headers: auth_headers
in my request specs.在我的请求规格中。
I first tried to test the 401 Unauthorized case by just removing auth_headers
, which then lead to the unexpected 302 Found response.我首先尝试通过删除
auth_headers
来测试401 Unauthorized案例,然后导致意外的302 Found响应。
However, testing my API via Postman worked as expected (401 response without auth header).但是,通过 Postman 测试我的 API 按预期工作(没有 auth 标头的 401 响应)。
The solution was to just remove the Authorization
header and keeping the Accept
header, so the application would know that it's not talking to a user and thus would not redirect to the login page:解决方案是仅删除
Authorization
标头并保留Accept
标头,因此应用程序将知道它不是在与用户交谈,因此不会重定向到登录页面:
let(:auth_headers) { Devise::JWT::TestHelpers.auth_headers({ 'ACCEPT': 'application/json' }, user) }
# ...
get "/api/v1/something", headers: { 'ACCEPT': 'application/json' }
I believe the issue is that devise returns HTTP 302 Redirect if the request is made from a browser, otherwise it returns 401 Unauthorized.我认为问题在于,如果请求是从浏览器发出的,devise 返回 HTTP 302 Redirect,否则返回 401 Unauthorized。
I believe the solution is to update the requests in your test file to look like this:我相信解决方案是将测试文件中的请求更新为如下所示:
put :update, topic_id: my_topic.id, id: my_post.id, post: {title: my_post.title, body: my_post.body}, as: :json
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.