Jonathan BarnesJonathan Barnes
Standup 08/19/2008
edit Posted by Jonathan Barnes on Tuesday August 19, 2008 at 04:25PM

Interesting Things

  • If your wanting better out-of-the-box error messaging you can use one or both of the following plugins:
    • active_record_full_messages_should_be_nicer
    • validates_associated_displaying_associated_errors

If you choose to use both however ORDER DOES MATTER (use the order specified above) otherwise the validates_associated one just doesn't seem to work.

  • Hash Iterations is very expensive (this includes my_hash.keys and my_hash.to_a etc...). We think this is related to the way hashes are stored in large, sparsely populated hashtables. If you can, avoid iterating over a hash, and if you must, try using a SequencedHash (which is provided by the collections gem) which solves this by storing hashes as both traditional hashtables and arrays, allowing for fast random access (the hashtable) as well as fast iteration (the array).

Ask for Help

"We want to load a different set of libraries for our selenium test than our regular tests. We tried to create a 'selenium' environment and pass that to the rake:test task but that didn't work, anyone know why?"

You cannot run in non 'test' environment with the rake tasks as the 'test' environment is hard coded into the test task, and passing a different RAILS_ENV seems to only have the effect of telling the 'test' environment what database to base it's schema off of.

Proposed work around - pass a second environment variable e.g. selenium=true and switch on that. (it's not ideal so we are still open to better solutions)

Comments

  1. joshua joshua on August 19, 2008 at 06:09PM

    Are those error messaging plugins internal pivitol projects? I cant find either in the wild.

  2. Chris Bailey Chris Bailey on August 19, 2008 at 06:25PM

    I can't find them either, and the validates associated one in particular has appeal to me.

  3. mw mw on August 19, 2008 at 06:40PM

    What kind of hashes (types of keys, size) do you talk about? I cannot see any advantage in SequencedHash.each and SequencedHash.each_key (except being 2.5 times and ~3 times slower than Hashs method), and while the hash loops are not fast (compared to array methods) I would not call them that bad.

    Probably I did something stupid, so my benchmark was

    #! /usr/bin/ruby
    
    $KCODE = 'u'
    
    require 'rubygems'
    require 'benchmark'
    require 'collections'
    
    array = []
    hash_int = {}
    hash_str = {}
    hash_rnd = {}
    hash_rnd_str = {}
    seq_hash = SequencedHash.new()
    
    n = 10000
    
    # note that the random hashes might be a bit smaller; we ignore that here...
    1.upto(1000) do | i | 
      array << i
      hash_int[i] = i 
      hash_str[i.to_s] = i
      hash_rnd[rand(1000000)] = i
      hash_rnd_str[rand(1000000).to_s] = i
      seq_hash[i] = i
    end
    
    Benchmark.bm(24) do | bm |
      bm.report('array') do n.times do; array.each { | i | } end end
      bm.report('hash(int)')  do n.times do; hash_int.each { | k,v | } end end
      bm.report('hash(str)')  do n.times do; hash_str.each { | k,v | } end end
      bm.report('hash(rnd int)')  do n.times do; hash_rnd.each { | k,v | } end end
      bm.report('hash(rnd str)')  do n.times do; hash_rnd_str.each { | k,v | } end end
      bm.report('seq hash(int)')  do n.times do; seq_hash.each { | k,v | } end end
      bm.report('hash(int) each_key')  do n.times do; hash_int.each_key { | k | } end end
      bm.report('hash(str) each_key')  do n.times do; hash_str.each_key { | k | } end end
      bm.report('hash(rnd int) each_key')  do n.times do; hash_rnd.each_key { | k | } end end
      bm.report('hash(rnd str) each_key')  do n.times do; hash_rnd_str.each_key { | k | } end end
      bm.report('seq hash(int) each_key')  do n.times do; seq_hash.each_key { | k | } end end
      bm.report('hash(int) keys')  do n.times do; hash_int.keys.each { | k | } end end
      bm.report('hash(str) keys')  do n.times do; hash_str.keys.each { | k | } end end
      bm.report('hash(rnd int) keys')  do n.times do; hash_rnd.keys.each { | k | } end end
      bm.report('hash(rnd str) keys')  do n.times do; hash_rnd_str.keys.each { | k | } end end
      bm.report('seq hash(int)')  do n.times do; seq_hash.keys.each { | k | } end end
    end
    
  4. Jonathan Barnes Jonathan Barnes on September 02, 2008 at 05:06PM

    Update: the error message helper plug-ins mentioned in this post are both currently pivotal internal plug-ins. They are both on the long list of pivotal source code that we plan to open source. You can keep an eye on the Pivotal.rb Rubyforge project, for when these particular plug-ins get released

  5. David Stevenson David Stevenson on September 09, 2008 at 10:39PM

    MW: I ran your benchmarks and a few of my own. Sequenced hash (which keeps an Array and a Hash) takes longer than both iterating over a hash or an array. Array is faster than fast. Hypothetically, sequenced hash should be as fast as Array iteration, but I guess it's not optimized as well (being written in ruby vs C).

    Good catch!