Generating a random alphanumeric string succinctly and efficiently
You could use
Array.new(8){[*'0'..'9', *'a'..'z', *'A'..'Z'].sample}.join

From the documentation for Array:

new(size=0, obj=nil) new(array) new(size) {|index| block }
Returns a new array. In the first form, the new array is empty. In the second it is created with size copies of obj (that is, size references to the same obj). The third form creates a copy of the array passed as a parameter (the array is generated by calling to_ary on the parameter). In the last form, an array of the given size is created. Each element in this array is calculated by passing the element’s index to the given block and storing the return value.

Perhaps it is better to create the array with the valid characters once in advance:
range = [*'0'..'9', *'a'..'z', *'A'..'Z']
Array.new(8){range.sample}.join


I made a Benchmark for the solutions.
require 'benchmark'
N = 10_000 #Number of Test loops

Benchmark.bmbm(10) {|b|
  
  b.report('Nat'      ) { N.times { ([nil]*8).map { ((48..57).to_a+(65..90).to_a+(97..122).to_a).sample.chr }.join } }
  b.report('tokland') { N.times { 8.times.map { [*'0'..'9', *'a'..'z', *'A'..'Z'].sample }.join } }
  b.report('knut'   ) { N.times { Array.new(8){[*'0'..'9', *'a'..'z', *'A'..'Z'].sample}.join } }
  b.report('Natinit') { 
    range = ((48..57).to_a+(65..90).to_a+(97..122).to_a)
    N.times { ([nil]*8).map { range.sample.chr }.join }
  }
  b.report('knutinit') { 
      range = ((48..57).to_a+(65..90).to_a+(97..122).to_a)
      N.times { Array.new(8){range.sample}.join }
  }

} #Benchmark

The result:
Rehearsal ---------------------------------------------
Nat         0.765000   0.000000   0.765000 (  0.765625)
tokland     2.172000   0.000000   2.172000 (  2.171875)
knut        1.953000   0.000000   1.953000 (  1.984375)
Natinit     0.063000   0.000000   0.063000 (  0.062500)
knutinit    0.078000   0.000000   0.078000 (  0.078125)
------------------------------------ total: 5.031000sec

                user     system      total        real
Nat         0.781000   0.000000   0.781000 (  0.781250)
tokland     1.953000   0.000000   1.953000 (  1.968750)
knut        1.922000   0.000000   1.922000 (  1.921875)
Natinit     0.063000   0.000000   0.063000 (  0.062500)
knutinit    0.078000   0.000000   0.078000 (  0.078125)

@Nat: Gratulation, your version is the fastest ;)
To analyze the fastest way to build the range I used the following benchmark:
Benchmark.bmbm(10) {|b|
  
  b.report('Natinit') { 
    N.times { ((48..57).to_a+(65..90).to_a+(97..122).to_a) }
  }
  b.report('knutinit') { 
      N.times { [*'0'..'9', *'a'..'z', *'A'..'Z'] }
  }
} #Benchmark

Result:
Rehearsal ---------------------------------------------
Natinit     0.093000   0.000000   0.093000 (  0.093750)
knutinit    0.250000   0.000000   0.250000 (  0.250000)
------------------------------------ total: 0.343000sec

    user     system      total        real
Natinit     0.094000   0.000000   0.094000 (  0.093750)
knutinit    0.219000   0.000000   0.219000 (  0.218750)