我一直试图让validates_uniqueness_of
为我的数据库工作。我从CSV文件中提取记录,我想确保记录它们,但是当我下次检查时,如果它们只是重复,我不想再将它们全部保存。
示例对象
PlayerStats {session_date, uniform_number, last_name, first_name, throws, throws_caught, throws_dropped, intercepted_throws, defended_throws }
示例记录
2013-01-01, 11A, Jacobsen, Mike, 11, 4, 7, 0 0
2013-01-01, 11A, Jacobsen, Mike, 0, 0, 0, 2, 1
我想保留这两个记录,但是当我尝试验证时......
validates_uniqueness_of :uniform_number, :scope => [:session_date, :last_name]
这只会保留第一条记录,并认为第二条记录是重复记录。 我希望在第二条记录进行保存尝试的时候,它也会保存第二条记录。
答案 0 :(得分:1)
问题是您只验证三个字段的唯一性,而不是所有字段。您应该将所有字段添加到:scope
。但是,如果你有一个包含太多行的表,那将不是非常好的性能。我建议您从要验证唯一性的所有字段中生成令牌,并在令牌上添加唯一性验证。沿着这条路线,你必须在你的表中再添加一列来存储计算出的令牌。不要忘记在列上添加唯一索引以获得最佳性能。在那之后应该做的诀窍:
before_validate :generate_unique_token
# assuming you named your slug column `unique_token`
validates :unique_token, uniqueness: true
private
# add all fields you want to validate uniqueness on
UNIQUE_FIELDS = [:uniform_number, :session_date, :more_fields]
def generate_unique_token
return if self.unique_token.present?
token_string = ''
# additional comma is to ensure that [1, 10] and [11, 0] don't get treated as same input
UNIQUE_FIELDS.each {|field| token_string << self.send(field).to_s << ','}
self.unique_token = token_string
end
此字符串可能变大,但您不会遇到任何错误的冲突。如果要控制生成的令牌的大小,可以执行以下操作:
def generate_unique_token
token_string = ''
UNIQUE_FIELDS.each {|field| token_string << self.send(field).to_s << ','}
self.unique_token = compress_token(token_string)
end
def compress_token(token_string)
# you can further compress the token by encoding it in base 62/64
::Digest::SHA256.hexdigest(token_string)
end
但要注意,后来的解决方案可能会发生罕见的错误碰撞。