确保应用程序级别的唯一列值

时间:2011-09-27 21:44:10

标签: ruby-on-rails ruby-on-rails-3 activerecord

我正在处理的Rails 3.1应用程序中的一个模型具有“代码”属性,该属性在创建记录时自动生成,并且必须是唯一的。应用程序应检查数据库以查看生成的代码是否存在,如果存在,则应生成新代码并重复该过程。

我可以使用add_index :credits, :code, :unique => true(我正在做的)以及validates_uniqueness_of的模型确保数据库级别的字段唯一性,但如果生成的代码,这两者都只会返回错误存在。我需要在重复的情况下再试一次。生成的代码足够长,不太可能重复,但我需要100%确定。

此代码生成透明地处理给最终用户,因此他们永远不会看到错误。一旦生成代码,检查它是否存在的最佳方法是什么,并重复该过程直到找到唯一值?

2 个答案:

答案 0 :(得分:4)

这是一个简单的例子,这里仍然存在技术上的竞争条件,但除非你每秒看到数百或数千个创建它真的不应该是一个担心,最坏的情况是你的用户如果运行了两个创建就会得到一个单一的错误这样一种方式,他们都执行查找和返回nil相同的Url

class Credit < ActiveRecord::Base
  before_validation :create_code, :if => 'self.new_record?'
  validates :code, :uniqueness => true

  def create_code
    self.code = code_generator
    self.code = code_generator until Credit.find_by_code(code).nil?
  end
end

如果您绝对需要删除竞争条件情况,其中两个创建正在串联运行并且都使用相同代码触发查找并返回nil,则可以使用需要特定于DB的SQL的表锁来包装查找,或者您可以通过悲观锁定创建一个用于锁定的行的表,但我不会那么远,除非你期望每秒创建数百个并且你绝对要求用户永远不会看到错误,它是可行的,只是一种在大多数情况下都是矫枉过正的。

答案 1 :(得分:0)

我不确定是否有内置方式。我一直使用before_create

以下是UrlShortener上下文中的示例。

class UrlShortener < Activerecord::Base
  before_create :create_short_url

  def create_short_url
    self.short_url = RandomString.generate(6)
    until UrlShortener.find_by_short_url(self.short_url).nil?
      self.short_url = RandomString.generate(6)
    end
  end
end
相关问题