Let's call it AdequateForm for now.
class SignUpForm < AdequateForm
attribute :first_name
attribute :last_name
attribute :birthdate, :date
validates :first_name, :birthdate, presence: true
end
form = SignUpForm.new(first_name: "Pavel")
form.last_name = "Pravosud"
form.attributes # => { first_name: "Pavel", last_name: "Pravosud", birthdate: nil }
form.valid? # => false
form.errors # => <ActiveModel::Errors {:birthdate=>["can't be blank"]}>
form.assign_attributes "birthdate(1i)" => "1986", "birthdate(2i)" => "8", "birthdate(3i)" => "25"
form.birthdate # => Mon, 25 Aug 1986
form.valid? # => true
form.update(first_name: nil) # => false, because invalid
form.update(first_name: "Pavel") # => true, all good
Also, some goodies:
class SomeOtherForm < AdequateForm
# copying attributes/validation data from AR models
copy_attributes_from Post
copy_validations_from Post
end