新手问题 自定义的 validate 居然在保存成功之后执行了。。。。

xiaobai2 · 2016年10月09日 · 最后由 leekelby 回复于 2017年03月23日 · 2804 次阅读

情况是这样的,我插入的最后一条是没法通过我自定义的 validate 的,但是。。。。 如上调试所示,正常情况下应该是只能插入一条数据的,但是插入第二条的时候,居然跳过了验证。第三条以后是正常的都不能插入,这是什么情况?

你该贴的是你 validate 的代码

@Catherine

validate :only_three_by_day
  def only_three_by_day
    if Notification::Send.where("send_date BETWEEN ? AND ? AND send_status != ?", send_date.beginning_of_day, send_date.end_of_day, 3).count > 3
      errors.add(:id, "一天之内只能发3条!")
    end
  end

  validate :only_one_by_hour
  def only_one_by_hour
    if Notification::Send.where("send_date BETWEEN ? AND ? AND send_status != ? ", send_date.beginning_of_hour, send_date.end_of_hour, 3).count > 1
      errors.add(:id, "1个小时之内只能发1条哦!")
    end
  end

#2 楼 @xiaobai2

  • 确认下你指定的 validate 方法有没有执行
  • 执行了,复现一下当时的场景,确定下 if 的条件是否符合你的预期

@jasl 首先 validate 确实执行了,我现在怀疑是我 if 条件的问题,可是感觉没问题啊,一个小时之内只能设置一条 send_date。我这有写真的没有看出毛病。。。。。。

#4 楼 @xiaobai2 是你的判断逻辑有问题。 你想要在一个小时内只能插入 1 条,但是你判断的是 count > 1,当你插入第二条时,此时 count 是 1 啊,并不满足你的条件。你应该判断 count == 1

5l 说的好 应该是判断大于等于 1 的情况 或者用 unless 判断count == 0的情况

@tesla_lee @hging @jasl 我改成>=1 了,现在确实只能添加一条数据,我的逻辑是添加成功之后到 render 到 show,他却给出了提示 我的 create 代码大概如下:

begin
  if @model.save!
    .....
  end
rescue Exception => e
  render :show
end

意思就是第一条可以添加成功,但是他也给报这样的验证提示 从逻辑上分析,还是先走了 save!,然后再从验证判断。。。。。 补充一句:如果我写成>=1 的话,我添加第一条肯定会走 errors.add 啊

我觉得是不是你 save 的逻辑有问题,在回调里面还有个 save

你试试给个一定会通过的 validate,看看你的数据会不会 save 两次

#8 楼 @IChou 我就是正常的 save 逻辑啊,按照你的要求也验证过了,如果我写成>=1 的话,我添加第一条肯定会走 errors.add

从你的截图看,COMMIT 成功的那次是走了你的 validate 的,而且通过了

然后又立马起了一个事务,又执行你的 validate,没有通过,于是事务回滚了,这个时候就会抛出你收到的报错

所以我推断你的 save 被发起了两次,看上去就出现了你所说的,数据都存了,然后才 validate 的现象

如果你只想在插入数据时验证应该用 validate :only_three_by_day, on: :create 否则 update 的时候,也会触发验证

#10 楼 @IChou 好吧,问题终于找到了,感谢。另外我想在 update 和 create 的时候走这个 validate 该怎么做? validate :only_three_by_day, on: [:create, :update] 吗? 我也没找到为什么唤醒了两次 save 操作

#11 楼 @xiaobai2 默认情况下,每次调用 valid? 方法时都会执行自定义的验证方法, :create, :update 都会调用

http://guides.ruby-china.org/active_record_validations.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81%E4%BD%BF%E7%94%A8%E7%9A%84%E6%96%B9%E6%B3%95

#12 楼 @IChou 想请教一下,自定义的 validation 在 before_create 后不会触发,在 before_validation 或者 after_validation 可以触发。不太懂

#13 楼 @ztt1991 #12 的文档中有啊

1.2 什么时候做数据验证?这一节

下列方法会做数据验证,如果验证失败就不会把对象存入数据库: create create! save save! update update! 爆炸方法(例如 save!)会在验证失败后抛出异常。验证失败后,非爆炸方法不会抛出异常,save 和 update 返回 false,create 返回对象本身。

加上 return false

class Aaa
  before_save :check_num

  def check_num
    errors.add(:id, '不能保存就对了')
    return false # 看这里
  end
end

errors, valid?, save 之间的关系不是那么的明确。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号