Watch the screencast

SecureRandom is a common solution for generating simple, random strings in Ruby. But is it always the optimal approach?

In this video I demonstrate how SecureRandom can actually be quite a slow and expensive way to generate random strings, and walk through the steps for creating your own PORO that suits your specific domain.

RandomRef class

class RandomRef

  CHARS = *'A'..'Z', *'0'..'9'

  attr_reader :string

  alias to_s string

  def initialize(length: 10)
    @string = CHARS.shuffle.take(length).join
  end

end

Benchmark

Here’s the benchmark setup and results on my machine:

require "benchmark"

require_relative "random_ref"
require "securerandom"

TIMES_RUN = 10_000

Benchmark.bmbm do |test|
  test.report("SecureRandom hex:") { TIMES_RUN.times { SecureRandom.hex(5).upcase } }
  test.report("SecureRandom alpha:") { TIMES_RUN.times { SecureRandom.alphanumeric(10).upcase } }
  test.report("RandomRef:") { TIMES_RUN.times { RandomRef.new.to_s } }
end
Rehearsal -------------------------------------------------------
SecureRandom hex:     0.017828   0.101192   0.119020 (  0.119230)
SecureRandom alpha:   0.063555   0.243703   0.307258 (  0.307377)
RandomRef:            0.013328   0.001197   0.014525 (  0.014526)
---------------------------------------------- total: 0.440803sec

                          user     system      total        real
SecureRandom hex:     0.019170   0.108771   0.127941 (  0.128621)
SecureRandom alpha:   0.064643   0.246745   0.311388 (  0.311942)
RandomRef:            0.013712   0.000642   0.014354 (  0.014404)

Update 16/11/2020

I realised that RandomRef will not return a truly random string, since it won’t have any repeat characters. While this isn’t a major problem, I’ve updated the episode code with a slight refactor that corrects this. Benchmarks for the updated version below:

class RandomRef

  CHARS = *'A'..'Z', *'0'..'9'

  attr_reader :string

  alias to_s string

  def initialize(length: 10)
    @string = length.times.map { CHARS.sample }.join
  end

end
Rehearsal -------------------------------------------------------
SecureRandom hex:     0.022391   0.142847   0.165238 (  0.167282)
SecureRandom alpha:   0.071716   0.281742   0.353458 (  0.354494)
RandomRef:            0.022149   0.001585   0.023734 (  0.024165)
---------------------------------------------- total: 0.542430sec

                          user     system      total        real
SecureRandom hex:     0.018336   0.117855   0.136191 (  0.136656)
SecureRandom alpha:   0.071869   0.282151   0.354020 (  0.356737)
RandomRef:            0.023950   0.000139   0.024089 (  0.024159)

Explore the code

Explore the code from this screencast here: https://github.com/Bodacious/HandyRailsTips-EpisodeCode

Blog Logo

Gavin Morrice

Full-stack developer, based in Scotland


Published

Image

Handy Rails Tips

Ruby on Rails tips and tutorials

Back to home