Rails:如何验证我的记录,以便没有两个记录是相同的?

时间:2013-07-04 00:17:52

标签: ruby-on-rails validation csv rails-activerecord

我一直试图让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]

这只会保留第一条记录,并认为第二条记录是重复记录。 我希望在第二条记录进行保存尝试的时候,它也会保存第二条记录。

1 个答案:

答案 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

但要注意,后来的解决方案可能会发生罕见的错误碰撞。