问题描述
我正在搜索有关构建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端点的情况下实现的好习惯?还是应该将该验证从模型中删除,并使其置于请求参数级别?
我已经看到了一些可以在模型级别上使用的宝石,但是我想知道是否有某种模式而不使用任何其他宝石。
解决方法
最简单的方法是在验证中使用: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,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