rubocopでは、loop + break を推奨されます。
loop + break版
class Nonce
def set_nonce
return true if nonce.present? # 上書きさせないためのガード
self.nonace = loop do
random_str = SecureRandom.urlsafe_base64
break random_str unless self.class.exists?(nonce: random_str)
end
end
end
while版
class Nonce
def set_nonce
return true if nonce.present? # 上書きさせないためのガード
begin
self.nonce = SecureRandom.urlsafe_base64
end while self.class.exists?(nonce: nonce)
end
end
before_create
or before_validation
以下のような感じで、validates
を書いている場合は、before_create
を使うと、validation に引っかかってしまうので、before_validation
を使う必要があります。
class SomeClass
validates :nonce, presence: true, uniqueness: true
before_validation :set_nonce
private
def set_nonce
return true if nonce.present?
self.nonce = loop do
random_str = SecureRandom.urlsafe_base64
break random_str unless self.class.exists?(nonce: random_str)
end
end
end
テストの例
# frozen_string_literal: true
require 'rails_helper'
describe Nonce, type: :model do
describe '#set_nonce' do
it do
nonce = Nonce.create!
expect(nonce.nonce.size).to eq(8)
end
it do
nonce = Nonce.new
expect(nonce.nonce).to be_nil
nonce.save!
expect(nonce.nonce.size).to eq(8)
end
it do
nonce = Nonce.create!
nonce_str = nonce.nonce
nonce.update!(updated_at: Time.current)
expect(nonce.nonce).to eq(nonce_str)
end
end
end