我正在尝试删除在我关注的控制器中使用的 @current_user 。我正在使用关注点来验证 JWT 并在关注点中设置 @current_user 。 JWT 由第三方进行签名和验证,因此我出于测试目的绕过了该步骤,但需要一种设置 @current_user 的方法。以下是我的以下文件:
app/controllers/concerns/secured.rb
module Secured
extend ActiveSupport::Concern
def authorize
token = token_from_request
return if performed?
validation_response = client.verify_token_from_third_party # this is an external api call
@decoded_token = validation_response.decoded_token[0][0]
@current_user = User.find_by(id: @decoded_token["sub"])
return unless (error = validation_response.error)
render json: { message: error.message }, status: error.status
end
end
app/controllers/books_controller.rb
class BookssController < ApplicationController
before_action :set_book, only: %i[ show update destroy ]
before_action :authorize
# POST /books
def create
@books = Book.new(book_params.merge({user_id: @current_user.id}))
if @book.save
render json: @book, status: :created, location: @book
else
render json: @book.errors, status: :unprocessable_entity
end
end
end
spec/controllers/book_spec.rb
require 'rails_helper'
RSpec.describe BooksController do
let(:current_user) { User.create(username: "Joe") }
before :each do
allow(controller).to receive(:authorize).and_return(current_user)
end
context 'book creation' do
it 'authenticated user can create book' do #
post :create, :params => { :book => {:name => "Some Book"} }
expect(response).to have_http_status(:created)
end
end
end
错误:
1) BooksController book creation authenticated user can create book
Failure/Error: @book = Book.new(book_params.merge({user_id: @current_user.id}))
NoMethodError:
undefined method `id' for nil:NilClass
# ./app/controllers/books_controller.rb:23:in `create'
# ./spec/controllers/book_spec.rb:11:in `block (3 levels) in <top (required)>'
Finished in 0.10782 seconds (files took 1.13 seconds to load)
1 example, 1 failure
我的目标是能够绕过 before_action :在规范中授权并自己设置@current_user
我尝试过.instance_variable_set、allows等的变体。我的预感是我可能必须重新设计关注点如何设置@current_user,但我还没能弄清楚
你可以像这样在控制器中模拟 current_user
user = create(:user) #FactoryBot
allow(controller).to receive(:current_user).and_return(user)