【问题标题】:validate_presence_of *before* before_validationvalidate_presence_of *before* before_validation
【发布时间】:2015-10-10 00:41:06
【问题描述】:

假设我有一个 before_validation 检查以确保名称的第一个字母是“y”:

before_validation :check_name_first_letter_is_y

但我想确保名字也存在:

validates :name, presence: true

但这将在验证是否存在名字之前运行 before_validation,对吗?在运行 before_validate 之前如何检查名称是否存在?

我可以试试:

after_validation :check_name_first_letter_is_y

但是如果我返回 false 会停止保存方法吗?还是因为已经过验证而为时已晚?

【问题讨论】:

  • 标准问题:为什么需要这样做? check_name_first_letter_is_y首字母不是y怎么办?

标签: ruby-on-rails validation


【解决方案1】:

按以下方式在一个电话中执行此操作可能会更容易(如果我没有误读您的问题!):

validates :name, presence: ->(rec) { rec.name.initial == 'Y' }

更新:

引入一个新的ActiveModel::EachValidator,它检查名称中的第一个字符是y,并像往常一样使用存在验证器,但确保存在验证器位于name验证器之前,以便在之前完成存在性检查检查第一个字母。

# app/validators/NameValidator.rb

class NameValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if value.initial != 'y'
      record.errors[attribute] << (options[:message] || "First letter in name must be `y`")
    end
  end
end

然后在您的模型中,使用以下两个验证:

validates :name, presence: true
valdiates :name, name: true

请参考:http://api.rubyonrails.org/classes/ActiveModel/Validator.html

还建议您为NameValidator 类取一个“Railsy”名称!

【讨论】:

  • 你能传递一个 lambda 作为验证器选项吗?
  • 嗯..我的实际情况比这要复杂一些,但我想我会简化问题
  • 我想知道是否必须将 validates :name, presence: true 切换为自定义验证,例如before_validation :name_present?
  • @JacksonCunningham,您可以对同一属性进行多次验证。记住顺序很重要。所以先检查存在,然后检查第一个字母而不是 before_validation。你不觉得这样应该更简单吗?
【解决方案2】:

您可以简单地添加第二个格式验证:

validates :name, presence: true, format: { with: /^y/, allow_blank: true }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多