Rails JSON API参数验证和错误响应

Cap*_*ggz 6 ruby ruby-on-rails 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
Run Code Online (Sandbox Code Playgroud)

现在,如果我想稍微复杂一点,可以添加以下内容

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

这使我们想到了我的问题。

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

An unhandled lowlevel error occurred. The application logs may have details.
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

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

Sem*_*jon 5

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

如果您打算仅使用 API 模式,我建议您有机会获得非常简洁的 API DSL https://github.com/ruby-grape/grape#parameter-validation-and-coercion


San*_*sen 5

我认为您将strong_parameters验证方法与混淆使用。

强大的参数提供了一个接口,用于保护属性免受最终用户分配。这使得Action Controller参数在被列入白名单之前禁止在Active Model质量分配中使用。

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
Run Code Online (Sandbox Code Playgroud)

所以你的例子:

POST /users body={user: {email: 'some@email.com', phone: '1234', some_other: 'some other'}}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

然后在您的模型中:

class User < ActiveRecord::Base
  validates_precense_of :some_other #this will cause the user not to save, end thus, report an errer message
end
Run Code Online (Sandbox Code Playgroud)