ActiveRecord 之自定义Validation

Rails中ActiveRecord是一套强大的ORM工具,今天介绍一下在其中自定义一个校验的方法。

自定义validate方法

请思考这样一个问题,Rails中自带的Validations能满足你所有的要求么?

如果不能,你可能需要自定义一些 validate 的方法。

我在实际写代码的过程中遇到这样一个情况,是有一张表叫做configs,其中两个字段:user_id, device_id,不同同时和另外一条记录的这两个字段相同。也就是说,我不能 validate_uniqueness_of :user_id, :device_id,因为这样只会单独检查user_id 和 device_id 是否有过重复,而不是检查是否同时重复。

所以我自定义了一个validate。代码大致如下:

# app/models/config.rb

validate :customed_validation, on: :create

def customed_validation
 if self.class.find_by(user_id: user_id, device_id: device_id)
    errors.add(:user_id, 'a customizable error message')
  end
end

这段代码是什么意思呢?首先 在 create 的过程中加入 validate,这个validate叫做 customed_validation ,然后我们在下面定义这个 customed_validation

customed_validation 中,如果验证不通过,就往 errors 中加入一个自定义的报错信息。然后,当这个报错真的被加进来的时候,你就可以通过 self.errors来打印这个错误信息。就像你 validates :title, presence: true一样。如果没有title,前端会打印 title is blank 这样的错误。只不过这里打印的错误是你自己定义的。剩下的就跟你常用的 validation 们(比如 presence, numericality)一样了。

其他定义方法

当然,如果你没有用 ActiveRecord,就不能直接用这样的validation,需要mix in一个ActiveModel::Validation的模块。这里不做更多说明(因为我也没有用过这种,哭哭),有需要的看这里。另外,我这里用的是自定义 validate 方法,你还可以自定义一个 validator (一种 ActiveModel::Validation的子类),这样就你就可以到处引用这个validator了。

后话

我在这里想讨论的是谁在调用validate中自定义的方法。

就拿我刚才给出的示例代码为例,在这个方法中,self是个 Config 的一个实例(但是这个对象没有存储到数据库中,是个刚刚初始化过的数据,一个证据是没有id。但他依然是一个Config实例化的对象)。所以在示例代码中的 errors 就相当于是 self.errors。也从这里可以看出来,这是一个实例方法(请定义的格式来看也是实例方法),不是类方法。

另外,你把这个方法变成private的实例方法依然没有问题。然而,并不是所有的实例方法都能放在private中。这个实例方法能,是因为没有在外部调用。如果你想在外部调用,或者,哪怕在这个model内部,用self来调用都是有问题的。如果你用了(在外部用Config的实例调用,或者在内部用self调用),Rails都会抛出异常说private方法被调用。对于钱一种情况,好理解,private方法嘛,就当它顾名思义了,虽然具体怎么实现的我还不知道;但是后一种怎么回事呢,我将在以后的ActiveRecord的文章中讨论。

Recall

  1. 引入validate
  2. 定义validate的具体方法
    validate :a_method, on: [:create]
    private
    def a_method
     if something?
        errors.add(:attribute, 'message')
     end
    end

你可能感兴趣的:(ActiveRecord 之自定义Validation)