Ruby on Rails - 生成数据库中不存在的随机数

时间:2017-07-16 10:02:59

标签: ruby ruby-on-rails-4 random model

在我的应用程序中,我有Case模型&用户生成的每个案例都有case_number

case_number是从我的Case模型生成的。目前我在创建case之后从我的模型中创建了一个3位数的随机数。

class Case < ActiveRecord::Base

  after_create :random_case_number

  private
    def random_case_number
      random_number = Random.rand(999)
      self.update_attributes(case_number: random_number)
    end
end

这导致一些案例具有相同的case_number。我怎样才能从我的模型中生成一个当前未使用的随机数&amp;如果所有3位数字都被采用,它可以移动到4位数,依此类推。

2 个答案:

答案 0 :(得分:1)

首先确保case_number在数据库中有唯一索引。

rails generate migration add_unique_index_to_case_number

编辑生成的迁移,看起来像这样:

class AddUniqueIndexToCaseNumbers < ActiveRecord::Migration[5.1]
  def change
    add_index(:cases, :case_number, unique: true)
  end
end

(您可能需要删除无效(重复)案例才能添加此索引)

这可确保不会向DB添加无效的案例编号。

然后我使用序列号而不是随机序列号。如果最终使用100 - 999的所有数字,那么使其随机化没有多大意义(并且3位数中没有太多熵,因此很容易猜出数字)。选择一个不存在的&#34;随机&#34;也有点麻烦。插入时的数字。

rails generate migration add_sequence_to_case_numbers

再次修改迁移:

class AddSequenceToCaseNumbers < ActiveRecord::Migration[5.1]

  def change
    execute <<-SQL
      CREATE SEQUENCE cases_case_number_seq;
      ALTER TABLE cases ALTER COLUMN case_number SET DEFAULT nextval('cases_case_number_seq');
    SQL
  end
end

答案 1 :(得分:0)

要生成随机数并确保数据库中不存在该数字,我会这样做:

before_create :assign_unique_case_number

validates! :case_number, uniqueness: true

private

CASE_NUMBER_RANGE = (10_000..99_999)

def assign_unique_case_number
  self.case_number = loop do
    number = rand(CASE_NUMBER_RANGE)
    break number unless Case.exists?(case_number: number)
  end
end

请注意,数据库中存在的情况越多,查找未使用的号码所需的时间就越长。因此我建议从一开始就使用更多数字。更多的数字还有另一个好处:他们很难猜测应用程序中可能有什么重要或可能不重要。

此外:Rails不能保证数据库中的唯一性。可能存在导致重复的竞争条件。避免这种情况的唯一方法是在迁移中向数据库列添加唯一索引,如下所示:

add_index :cases, :case_number, unique: true