如何在 Rails API 模型上应用验证版本控制?
How to apply validation versioning on Rails API models?
我正在搜索有关构建 Rails API 以及如何在模型验证上正确应用某些版本控制的信息。
假设有这样的模型和路线:
class Person < ApplicationRecord
validates :name, presence: true
end
namespace :v1
resources :people
end
因此,我的模型正在验证 name
是否存在。
但是,如果我想发布我的 API 的新版本,并在 Person
上进行新的验证,例如,job
字段是强制性的,就像这个:
class Person < ApplicationRecord
validates :name, presence: true
validates :job, presence: true
end
如果我这样做,我会破坏我的 V1 端点。那么,是否有一种好的做法可以在不破坏我以前的 V1 端点的情况下实现它?还是我应该将此验证从模型中删除并在请求参数级别进行验证?
我看到一些 gems 在模型级别制作它,但我想知道是否有一些模式,而不使用任何额外的 gem。
实现此目的的最简单方法是在验证中使用 :on
选项并执行上下文验证,例如
class Person < ApplicationRecord
validates :name, presence: true
validates :job, presence: true, on: :v2
end
然后您可以在 v1 端点中使用 person.valid?
并在 v2 端点中使用 person.valid?(:v2)
。
但此解决方案仅适用于简单场景,无法在长期或更复杂的应用程序中扩展。
更好的解决方案是提取验证逻辑以形成从您的参数创建的对象,并为包含一些重大更改的端点的每个版本提供单独的表单对象,例如:
class PersonV1Form
include ActiveModel::Validations
attr_accessor :name, :job
validates :name, presence: true
def initialize(params = {})
@name = params[:name]
@job = params[:job]
end
end
class PersonV2Form
include ActiveModel::Validations
attr_accessor :name, :job
validates :name, :job, presence: true
def initialize(params = {})
@name = params[:name]
@job = params[:job]
end
end
然后在您的控制器中,您可以在使用表单对象为您的模型提供数据之前验证表单对象:
module V1
class PeopleController < ApplicationController
def create
person = PersonV1Form.new(params[:person])
if person.valid?
# ...
end
end
end
end
module V2
class PeopleController < ApplicationController
def create
person = PersonV2Form.new(params[:person])
if person.valid?
# ...
end
end
end
end
我正在搜索有关构建 Rails API 以及如何在模型验证上正确应用某些版本控制的信息。
假设有这样的模型和路线:
class Person < ApplicationRecord
validates :name, presence: true
end
namespace :v1
resources :people
end
因此,我的模型正在验证 name
是否存在。
但是,如果我想发布我的 API 的新版本,并在 Person
上进行新的验证,例如,job
字段是强制性的,就像这个:
class Person < ApplicationRecord
validates :name, presence: true
validates :job, presence: true
end
如果我这样做,我会破坏我的 V1 端点。那么,是否有一种好的做法可以在不破坏我以前的 V1 端点的情况下实现它?还是我应该将此验证从模型中删除并在请求参数级别进行验证?
我看到一些 gems 在模型级别制作它,但我想知道是否有一些模式,而不使用任何额外的 gem。
实现此目的的最简单方法是在验证中使用 :on
选项并执行上下文验证,例如
class Person < ApplicationRecord
validates :name, presence: true
validates :job, presence: true, on: :v2
end
然后您可以在 v1 端点中使用 person.valid?
并在 v2 端点中使用 person.valid?(:v2)
。
但此解决方案仅适用于简单场景,无法在长期或更复杂的应用程序中扩展。
更好的解决方案是提取验证逻辑以形成从您的参数创建的对象,并为包含一些重大更改的端点的每个版本提供单独的表单对象,例如:
class PersonV1Form
include ActiveModel::Validations
attr_accessor :name, :job
validates :name, presence: true
def initialize(params = {})
@name = params[:name]
@job = params[:job]
end
end
class PersonV2Form
include ActiveModel::Validations
attr_accessor :name, :job
validates :name, :job, presence: true
def initialize(params = {})
@name = params[:name]
@job = params[:job]
end
end
然后在您的控制器中,您可以在使用表单对象为您的模型提供数据之前验证表单对象:
module V1
class PeopleController < ApplicationController
def create
person = PersonV1Form.new(params[:person])
if person.valid?
# ...
end
end
end
end
module V2
class PeopleController < ApplicationController
def create
person = PersonV2Form.new(params[:person])
if person.valid?
# ...
end
end
end
end