Reputation: 51
I mean not to check on saving is current value - unique.
How can I create value (for example in my model), check is it unique for my table. Anf id not than try to create new value maybe. And check the uniqueness again
Now I have the following code in my model:
after_initialize :init
def init
self.some_field = rand(1..99_999_999).to_s
end
Upvotes: 0
Views: 857
Reputation: 518
You can use model callback like,
before_create :generate_some_field
def generate_some_field
self.some_field = loop do
random = rand(1..99_999_999).to_s
break random unless ModelName.exists?(some_field: random)
end
end
Upvotes: 2
Reputation: 116
I recently wrote a gem to solve this problem for myself: https://github.com/inem/shufflino
No retries or extra SQL query needed with this approach.
I also recommend watching this talk on the topic.
Upvotes: 1
Reputation: 99
Add a validation for uniqueness, and initialize the field before validation. Add a max retries limit to avoid possible deadlocks when number of records approaches or reaches max number of possible random values.
INITIALIZATION_MAX_RETRIES = 10
before_validation :initialize_fields
validates_uniqueness_of :some_field
private
def initialize_fields
unless some_field
retries = 0
loop do
retries += 1
break if retries > INITIALIZATION_MAX_RETRIES
self.some_field = rand(1..99_999_999).to_s
break unless self.class.find_by(some_field: some_field)
end
end
end
Upvotes: 1
Reputation: 16464
Add a validation
Then set the value, check it,
if good: it's done.
if not: try again, repeating a reasonable number of times.
Something like this
validates :some_field, uniqueness: true
def init
attempts = 0
loop do
self.some_field << SecureRandom.uuid.to_s[0..16]
self.valid?
break unless self.errors[:some_field].any?
attempts = attempts + 1
if attempts > 3
self.errors[:some_field] << "Could not generate a unique value after #{attempts} attempts"
break
end
end
end
Upvotes: 1