选择在哪里放置验证?
Choosing where to put validations?
考虑来自 the "Getting Started" guide 的这个片段:
module Web::Controllers::Books
class Create
include Web::Action
expose :book
params do
param :book do
param :title, presence: true
param :author, presence: true
end
end
def call(params)
if params.valid?
@book = BookRepository.create(Book.new(params[:book]))
redirect_to '/books'
end
end
end
end
请注意 title
和 author
上的验证,它们存在于控制器操作中。我的问题是:为什么这些验证是针对操作参数而不是 Book
实体?也就是说,假设验证 是 Book
,你可以这样写:
def call(params)
book = Book.new(params)
if book.valid?
@book = BookRepository.create(Book.new(params[:book]))
redirect_to '/books'
end
end
并完全摆脱 params
块。这对我来说似乎更自然,并且会促进跨不同操作更容易地重用验证。
params
方法是否有我没有发现的优势?对 Book
实体进行验证是否有缺点?
官方指南中的 Validations & Coercion 部分解释了为什么你应该对你的请求进行验证,而不是对你的模型进行验证。
总结一下,主要有以下两个原因:
从架构的角度来看,永远不应允许无效输入进入您的系统,因此最好在控制器级别完全跳过它们,而不是创建一个仅用于验证的模型,因为这是相当昂贵的操作。
可以有多个请求在同一模型上工作。如果您在模型级别进行验证,您还需要考虑这些请求的不同场景,这也是控制器的责任,而不是模型的责任。
不过,如果您的业务逻辑中可以使用上述场景,那将归结为个人喜好问题。
考虑来自 the "Getting Started" guide 的这个片段:
module Web::Controllers::Books
class Create
include Web::Action
expose :book
params do
param :book do
param :title, presence: true
param :author, presence: true
end
end
def call(params)
if params.valid?
@book = BookRepository.create(Book.new(params[:book]))
redirect_to '/books'
end
end
end
end
请注意 title
和 author
上的验证,它们存在于控制器操作中。我的问题是:为什么这些验证是针对操作参数而不是 Book
实体?也就是说,假设验证 是 Book
,你可以这样写:
def call(params)
book = Book.new(params)
if book.valid?
@book = BookRepository.create(Book.new(params[:book]))
redirect_to '/books'
end
end
并完全摆脱 params
块。这对我来说似乎更自然,并且会促进跨不同操作更容易地重用验证。
params
方法是否有我没有发现的优势?对 Book
实体进行验证是否有缺点?
官方指南中的 Validations & Coercion 部分解释了为什么你应该对你的请求进行验证,而不是对你的模型进行验证。
总结一下,主要有以下两个原因:
从架构的角度来看,永远不应允许无效输入进入您的系统,因此最好在控制器级别完全跳过它们,而不是创建一个仅用于验证的模型,因为这是相当昂贵的操作。
可以有多个请求在同一模型上工作。如果您在模型级别进行验证,您还需要考虑这些请求的不同场景,这也是控制器的责任,而不是模型的责任。
不过,如果您的业务逻辑中可以使用上述场景,那将归结为个人喜好问题。