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),但是对于验证参数的存在仍然存在问题。
“Rails 方式”应该使用表单往返 - 所有验证都应该存在于模型中。控制器可能只有简单的验证,例如安全性和白名单,与业务逻辑无关。“模型”可能不仅是 ActiveRecord 本身,还可能是 FormObject https://robots.thoughtbot.com/activemodel-form-objects之类的东西,特别是如果您的某些资源未一对一反映到数据库表中。
如果您打算仅使用 API 模式,我建议您有机会获得非常简洁的 API DSL https://github.com/ruby-grape/grape#parameter-validation-and-coercion
我认为您将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)