Rails JSON API参数验证&错误回复

时间:2016-07-18 08:46:58

标签: ruby-on-rails ruby ruby-on-rails-5

我是Rails的新手,有几个关于验证参数和返回错误响应的问题。我想使用新的Rails 5 API模式创建一个JSON API。

据我所知,Rails建议使用“强参数”作为验证参数的基线。例如,如果我想创建一个需要电话号码或电子邮件的User类,我会在UsersController中以类似的方式开始。

def create
  @user = User.new(create_user_params)
end

def create_user_params
  params.require(:user).permit(:email, :phone)
end

现在,如果我想要更复杂的东西,我可以添加以下内容

def create
  arr_contains_at_least_one(params[:user], [:email, :phone])
  @user = User.new(create_user_params)
end

这引出了我的问题。

在出现默认Rails错误(ActionController :: ParameterMissing)或自定义错误的情况下,返回“漂亮”错误响应的最佳方法是什么?我的意思是,如果我在浏览器中调用API端点,它将返回带有描述性消息的可读JSON。如果我在生产模式下运行我的服务器,并且在第一个示例中未能提供用户参数,则rails返回:

An unhandled lowlevel error occurred. The application logs may have details.

这显然不好,特别是如果我希望向最终用户显示错误。在这里,我假设强参数模式是为了安全性和数据完整性,而不是用户体验。模型字段验证似乎也是如此。所以我做了以下调整。

def create
  return error_response("some error") unless arr_contains_at_least_one(params[:user], [:email, :phone])
  @user = User.new(create_user_params)
end

def error_response(msg, status = 400)
  render json: {"code":status, "message": msg}, :status => status 
end

这有效,但现在我不得不手动编写参数检查(检查是否存在强制参数,以及验证电子邮件地址等参数)及其相应的错误响应。如果我也在模型上使用Rails的内置字段验证,这似乎违反了DRY原则。此外,设计良好的错误处理模式需要相当多的自定义实现。

我错过了一些Rails魔术还是我在正确的轨道上?

编辑:看起来主动记录验证可以很容易地包装在JSON响应中(http://guides.rubyonrails.org/active_record_validations.html),但仍然存在验证参数是否存在的问题。

2 个答案:

答案 0 :(得分:3)

我认为您对strong_parameters与验证方法的使用感到困惑。

  

强参数提供了一个界面,用于保护属性不受最终用户分配的影响。这使得动作控制器参数被禁止在活动模型批量分配中使用,直到它们被列入白名单。

http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

如果将参数列入强参数白名单,则表示您可以将它们大量分配给ActiveRecord模型。或者更好的是,未列入白名单的属性不会传递给您的模型。

它们实际上与验证本身无关。它们旨在保护您的模型以进行不允许的参数注入。

def create
  @user = User.new(create_user_params)
end

def create_user_params
  params.require(:user).permit(:email, :phone)
end

所以你的例子:

POST /users body={user: {email: 'some@email.com', phone: '1234', some_other: 'some other'}}

some_other属性不会传递到您的User.new

您正在寻找的是IS activerecord验证。在你的具体情况下,我会写一些类似的东西:

def create
  @user = User.new(create_user_params)
  if @user.save
    render json: @user
  else
    render @user.errors.full_messages.as_json, status: 400
  end
end

def create_user_params
  params.require(:user).permit(:email, :phone)
end

然后在你的模型中:

class User < ActiveRecord::Base
  validates_precense_of :some_other #this will cause the user not to save, end thus, report an errer message
end

答案 1 :(得分:1)

&#34; Rails方式&#34;应该使用表单往返 - 所有验证应该存在于模型中。控制器可能只有简单的验证,如安全性和白名单,与业务逻辑无关。 &#34;型号&#34;可能不仅是ActiveRecord本身,而且还有类似FormObject https://robots.thoughtbot.com/activemodel-form-objects的东西,特别是如果你的一些资源没有一对一地反映到数据库表中。

如果您打算只使用API​​模式,我建议您给一个非常整洁的API DSL机会 https://github.com/ruby-grape/grape#parameter-validation-and-coercion