Rails控制器如何校验传入查询参数的合法性(authorIds、postId)
Rails控制器接口参数校验实现
index接口authorIds参数校验
原实现存在两个问题:一是没有校验authorIds的格式,传入空值、特殊字符、非数字ID时会生成无效查询条件;二是posts是ActiveRecord查询关系对象,永远不会为nil,原有的if posts判断完全无效。
修改后代码:
def index # 校验参数非空 return render json: { error: "authorIds为必填参数" }, status: :bad_request unless params[:authorIds].present? # 分割参数后过滤出合法数字ID raw_ids = params[:authorIds].to_s.split(',').map(&:strip) valid_author_ids = raw_ids.filter { |id| id.match?(/^\d+$/) }.map(&:to_i) # 无合法ID时直接返回参数错误 return render json: { error: "authorIds需传入逗号分隔的合法用户数字ID" }, status: :bad_request if valid_author_ids.empty? posts = Post .get_posts_by_user_id(valid_author_ids) .order(sort_column => sort_direction) render json: { posts: posts }, status: :ok end
校验逻辑说明:
- 首先拦截空的authorIds参数
- 按逗号分割参数后去除首尾空格,通过正则匹配只保留纯数字格式的ID,转成整数类型
- 如果过滤后没有有效ID,说明传入参数全为非法值,直接返回400错误,避免无效数据库查询
- 移除了原有的无效posts空判断,因为查询关系对象即使返回空结果也不会是nil
update接口postId参数校验
原实现存在三个问题:一是传入非数字格式的ID时,查询不会报错但会返回nil,后续调用update!会触发空指针500错误;二是使用update!方法在校验失败时会直接抛出异常,无法走正常的错误返回分支;三是没有对找不到帖子的场景做显式404返回。
参考参数规则:

修改后代码:
def update # 校验ID格式合法性 return render json: { error: "postId必须为合法数字ID" }, status: :bad_request unless params[:id].to_s.match?(/^\d+$/) post = current_user.posts.find_by(id: params[:id].to_i) # 校验帖子存在且属于当前用户 return render json: { error: "目标帖子不存在或无操作权限" }, status: :not_found unless post if post.update(post_params) post_hash = post.as_json post_hash.merge!(authorIds: params[:authorIds]) if params[:authorIds].present? render json: { post: post_hash }, status: :ok else render json: { error: post.errors.full_messages }, status: :unprocessable_entity end end
校验逻辑说明:
- 首先校验传入的
params[:id]为纯数字格式,拦截字符串、特殊字符等非法ID - 查询帖子后判断是否存在,不存在则返回404权限/资源不存在错误
- 将
update!替换为update,数据校验失败时不会抛出异常,正常返回422错误和校验信息 - 增加authorIds非空判断,避免空值合并到返回结果中
可选优化
如果项目中多个接口需要做数字ID校验,可以把通用校验逻辑抽成控制器私有方法,通过前置过滤器统一调用,减少重复代码:
private # 通用数字ID校验方法 def valid_numeric_id?(param_key = :id) params[param_key].to_s.match?(/^\d+$/) end
调用示例:
before_action only: [:update] do render json: { error: "非法ID格式" }, status: :bad_request unless valid_numeric_id?(:id) end
内容的提问来源于stack exchange,提问作者Jose Cantu
相关产品推荐
相关产品推荐

