【发布时间】:2019-02-21 05:01:14
【问题描述】:
我有以下 rails_spec 测试:
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
fixtures :users, :clients
include AuthHelper
before do
@request.headers["Content-Type"] = 'application/json'
@request.headers["Accept"] = 'application/json'
end
describe '#create' do
context 'for a user with a valid authorization token' do
context 'having admin privileges' do
before do
init_headers_for_admin
end
context 'submitted with a valid set of parameters' do
it 'should create a new user having the submitted parameters' do
post :create, params: {
:name => 'Roland Deschain',
:email => 'roland@foamfactorybrewing.com',
:role => 'user',
:username => 'roland'
}
expect(response).to have_http_status(:ok)
user = json
expect(user).to_not be_nil
expect(user.name).to eq('Roland Deschain')
expect(user.email).to eq('roland@foamfactorybrewing.com')
expect(user.role).to eq('user')
expect(user.username).to eq('roland')
expect(user.created_at).to eq(user.updated_at)
end
end
我还有以下控制器定义:
def create
# get_required_fields.each { |field|
# unless params.has_key? field
# render :json => { :error => 'A ' + field.to_s + ' must be specified in order to create a new User'}, :status => :unprocessable_entity and return
# end
# }
username = params[:username]
unless User.find_by_username(params[:username]) == nil
render :json => { :error => I18n.t('error_username_conflict') }, :status => :conflict and return
end
unless User.find_by_email(params[:email]) == nil
render :json => { :error => I18n.t('error_email_conflict') }, :status => :conflict and return
end
end
但是,当我运行测试时,params 变量始终是一个空哈希。如果我取消注释检测我是否具有所需参数的代码,它总是返回UNPROCESSABLE_ENTITY,而不是NO_CONTENT,如果username、name 和email 存在,我会期望。我不太清楚为什么,但我似乎无法让它通过post 方法传递实际数据。我一直在看这个,并试图调试它,但我似乎无法让它正确传递参数。
我正在使用 Rails 5 和 rspec_rails 3.8.1。
编辑:
这里确实有问题,因为如果我将create 简化为:
def create
unless params.has_key?('name') && params.has_key?('username') && params.has_key?('email')
render :json => {:error => I18n.t('error_must_specify_username_email_and_name')}, :status => :unprocessable_entity and return
end
结束
并执行与以前相同的规范(显然希望它返回 no_content,而不是 unprocessable_entity),我最终会发生同样的事情 - 在调试模式下,它看起来像 params 进入变量这个方法是:
{"controller"=>"users", "action"=>"create", "user"=>{}}
所以,首先,它设置了user 参数,这不是我想要的完全,而且,它设置为一个空哈希。我不确定是什么原因造成的。我觉得这是我在 Rails 5.0 中忘记做的事情,因为这种模式在 Rails 4.0 中似乎可以正常工作。
编辑 2:
我将测试修改为:
it 'should create a new user record' do
post :create, params: { user: @user }, as: :json
expect(response).to have_http_status(:ok)
expect(json.name).to eq(@user.name)
expect(json.email).to eq(@user.email)
expect(json.username).to eq(@user.username)
expect(json.role).to eq(@user.role)
end
并将UsersController 类修改为如下所示:
class UsersController < ApplicationController
include AuthHelper
before_action :validate_api_key_for_auth, only: :login
before_action :authenticate_as_admin, only: [:create]
def create
p user_params
unless user_params.has_key?('name') && user_params.has_key?('username') && user_params.has_key?('email')
render :json => {:error => I18n.t('error_must_specify_username_email_and_name')}, :status => :unprocessable_entity and return
end
end
def user_params
params[:user].permit([:username, :name, :email, :role]).to_h
end
end
它正在打印出:{} 用于来自 user_params 的 users 哈希,但我不明白为什么会这样。
编辑 3:
authenticate_as_admin 以某种方式搞砸了参数。如果我将authenticate_as_admin 的定义更改为true,它会显示正确的哈希并按预期返回no_content。 authenticate_as_admin函数的定义如下(在ApplicationController中定义):
def authenticate_as_admin
authenticate_as :admin
end
def authenticate_as(role)
# First, get the headers for the request
authorization_header = get_authorization_header
unless authorization_header
render :json => {:error => I18n.t('error_must_be_logged_in')}, :status => :forbidden and return false
end
auth_token = authorization_header.split[1]
decoded_token = decode_authorization_header authorization_header
unless decoded_token
render :json => {:error => I18n.t('error_invalid_token')}, :status => :forbidden and return false
end
payload = decoded_token[0]
user_id = payload['user_id']
auth_token_expiration_date = payload['expiration_date']
@authenticated_user = User.find(user_id) rescue nil
unless @authenticated_user and @authenticated_user.auth_token == auth_token
render :json => {:error => I18n.t('error_must_be_logged_in')}, :status => :forbidden and return false
end
if auth_token_expiration_date < DateTime.now
render :json => {:error => I18n.t('error_auth_token_expired')}, :status => :forbidden and return false
end
unless @authenticated_user.role_at_least? role
render :json => {:error => I18n.t('error_insufficient_permission')}, :status => :forbidden and return false
end
true
end
我似乎不明白为什么这会弄乱参数,特别是考虑到这在 Rails 4.2 中运行良好。有人看到我遗漏的任何东西吗?
编辑 4:
我觉得我在正确的轨道上。似乎authenticate_as() 函数返回false,我得到了这种行为。如果before_action 返回false,控制器操作的预期结果应该是什么?我希望before_action 中调用的方法会执行适当的render ... 调用,而before_action 会默默地失败,永远不会调用本来会调用的函数。我仍然不太确定函数失败的原因,但我试图了解 应该 发生的行为。也许身份验证检查不是 Rails 5 中 before_actions 的一个很好的用例?
【问题讨论】:
-
控制器中是否允许使用 params 方法?它有一些
require部分吗?看起来你需要在规格中传递params: { user: { name: ...} } -
我尝试添加一个名为
user_params的方法,它允许所有参数(即params.permit!到UsersController,以及使用它代替直接参数,但没有运气. -
我认为这是因为:blog.bigbinary.com/2016/02/13/… 我还不知道如何让
before_action执行render的错误消息 + json,而不仅仅是在执行throw :abort时崩溃。 -
拒绝我的最后评论。情况似乎并非如此。我认为这解决了它,但这只是我疲倦的眼睛在另一次测试中欺骗了我。回到绘图板。
标签: ruby-on-rails ruby parameters