Ruby on rails 在保存前回调中更改属性以通过验证?

Ruby on rails 在保存前回调中更改属性以通过验证?,ruby-on-rails,validation,rails-activerecord,Ruby On Rails,Validation,Rails Activerecord,我有一个具有iv属性的组织模型。如果未设置iv,则它是随机的,但它必须是唯一的。首先想到的是下面的回调。它不起作用,因为有效?将尝试重新验证 class Organization < ActiveRecord::Base validates :iv, uniqueness: true before_save :set_default_iv def set_default_iv self.iv ||= random(1000) ### is it possib

我有一个具有
iv
属性的
组织
模型。如果未设置
iv
,则它是随机的,但它必须是唯一的。首先想到的是下面的回调。它不起作用,因为
有效?
将尝试重新验证

class Organization < ActiveRecord::Base
  validates :iv, uniqueness: true
  before_save :set_default_iv

  def set_default_iv
    self.iv ||= random(1000)

    ### is it possible to validate like this?
    # self.iv = random(1000) until valid?
 end
类组织
按照建议使用UUID生成器,或者自己使用某种算法检查唯一性(下面的示例)。但是在验证之前,请在
回调中执行此操作,这样验证器将捕获任何错误

before_validation :set_default_iv

def set_default_iv
  self.iv = random(1000) until iv.present? && !collisions_exist?
end

def collisions_exist?
  class.where({:iv => iv}).
        where(new_record? ? {} : ['id != ?', id]).exists?
end

请注意,此算法的性能将随着表的增长而降低,并且冲突更可能发生。因此,UUID生成器肯定是推荐的方法,优于
random(1000)
,因为您根本不需要手动检查碰撞。

您是否尝试过在验证前使用
而不是在保存前使用
?在我看来,验证前使用
似乎没有任何作用,因为它不能保证唯一性,只检查iv是否已经设置。如果您在验证前这样做,然后您的验证器将检查它是否唯一。如果你想说的是你总是想要一些独特的东西,并且没有重复命中的机会,那么你可能想研究一些更像UUID的东西,它比
random(1000)
@AlexeiDanchenkov具有更低的发生碰撞的可能性:验证程序的工作是保证唯一性,但不要更改该值以使其唯一,而是在不唯一时引发错误。通常,before_validation回调的工作是使用某种算法来确保验证器得到满足。然而,调用
有效?
不能成为该算法的一部分,因为这将调用验证器本身。@PinnyM:你说得对。从分配中删除缓存解决了这个问题<在我看来,验证前的代码似乎用词不当。如果你回答我的意见,我会接受的。如果您能帮助我进行缓存分配,我将不胜感激(如果已经设置了iv,并且它是唯一的,那么它应该保持不变,而不是随机化)。