提问人:CodingNewbie 提问时间:12/17/2022 最后编辑:Keivan SoleimaniCodingNewbie 更新时间:12/19/2022 访问量:328
使用 params.require 时,如何获得更具体的 400 验证错误而不是 500 错误?
How can I get a more specific 400 validation error instead of a 500 error when using params.require?
问:
我正在使用后端的 Rails 和前端的 React 完成一个全栈项目。我有一个注册表单,用于接受新用户的信息和头像,并将其传递给后端的用户控制器。但是,无论出于何种原因,如果表单为空或不完整,则会抛出 500 内部服务器错误,而不是信息量更大的 400 错误。
用户控制器是:
`` UsersController 类 < ApplicationController rescue_from ActiveRecord::RecordInvalid,替换为::render_unprocessable_entity_response
def 指数 用户 = User.all 渲染 json:用户 结束
def 创建 用户 = User.create(user_params) 会话[:user_id] = user.id 渲染 json: user, status: :created 结束
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :birthday, :username, :password, :password_confirmation, :avatar)
end
def render_unprocessable_entity_response(invalid)
render json: { errors: invalid.record.errors.full_messages }, status: :unprocessable_entity
end
end
React 中的注册表单(特别是我的 Submit 函数)
function handleSubmit(event) {
event.preventDefault();
const data = new FormData();
data.append("[user][first_name]", firstName);
data.append("[user][last_name]", lastName);
data.append("[user][email]", email);
data.append("[user][username]", username);
data.append("[user][password]", password);
data.append("[user][password_confirmation]", passwordConfirmation);
data.append("[user][avatar]", avatar);
fetch("/signup", {
method: "POST",
body: data
})
.then((response) => {
if (response.ok) {
response.json().then((user) => onLogin(user));
} else {
response.json().then((errorData) => contextData.setErrors(errorData.errors));
}
})
};
当我提交空表单时,我在控制台中得到的响应:
Parameters: {"user"=>{"first_name"=>"", "last_name"=>"", "email"=>"", "username"=>"", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "avatar"=>""}}
Completed 500 Internal Server Error in 97ms (ActiveRecord: 49.6ms | Allocations: 9234)
当我删除“params.require(:user)”部分时,它给了我预期的验证错误,但由于 ActiveStorage 工作并且需要数据,我无法创建新用户。
答:
这个问题的前提有很多错误,所以请耐心等待。
首先,让我们看一下以下文档:ActionController::Parameters#require
确保参数存在。如果存在,则返回 参数,否则会引发一个 ActionController::P arameterMissing 错误。
Rails 将在框架级别上挽救此错误,但您可以使用 在每个控制器级别上挽救它。但请记住,目的不是验证。如果请求缺少正确的结构并且无论如何都不应该被处理,那么它只是为了尽早保释 - 因为经典的 Rails 应用程序默认将其参数嵌套在与资源同名的键中。rescue_from 'ActionController::ParameterMissing'
require
在 API 应用程序中,您甚至不必遵循该模式 - 您也可以使用“平面参数”或 JSONAPI.org 等标准。
然后是使用:
rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response
这不时出现,作为一种“聪明”的方式来干燥 API。在你的情况下,它甚至不会起作用,因为不提高 - 确实。User.create
User.create!
这也不是对异常的良好使用。对于应导致立即停止执行的异常事件,应使用异常。传递无效输入的用户在任何方面都不是例外 - 事实上,它完全是平凡的。
如果您想以一种好的方式干燥您的 API,请按照 Responders gem 的方式进行:
class UsersController < ApplicationController
def create
user = User.create(user_params)
session[:user_id] = user.id
respond_with(user)
end
end
class ApplicationController
# ...
private
def respond_with(resource)
if resource.valid?
resource.new_record? ? render_created_response(resource) : render_updated_response(resource)
else
render_unprocessable_entity_response(resource)
end
end
def render_created_response(resource)
render json: resource, status: :created
end
def render_updated_response(resource)
render json: resource, status: :ok
end
end
这将创建一个可在子类中重写的方法的显式流。而不是由实际回调创建的隐式流。
class UsersController < ApplicationController
private
def render_updated_response
# do something wild and craazy
end
end
保留 的用途,用于不应预期创建记录会失败(例如在种子文件或非交互式上下文中)或导致事务内部回滚的上下文。create!
评论