Rails 3, Webrick, Mac OS X, Error: missing :action (ArgumentError)

I was making some changes in a routes.rb file and fat fingered the wrong line:

match '/public_html', "domains#public_html", :as => 'public'

Ran rails server, hit localhost:3000 and quickly saw a huge stack trace with this little gem of an error at the top:

/Users/miker/projects/projects/logthingy/vendor/bundle/ruby/1.8/gems/actionpack-3.0.7/lib/action_dispatch/routing/mapper.rb:171:in `default_controller_and_action': missing :action (ArgumentError)

To me, that error message is not the most helpful. Because the only change I had made was in routes.rb I knew the issue was there. By the way, this is where I feel a little bit sorry for newcomers to Ruby and Rails… The error messages are not always entirely clear. For those of us who have been in Ruby long enough to know the “breadcrumb logic” we can get by, but for those who don’t it can be a nightmare.

The fix was simple and subtle… was missing some punctuation:

match '/public_html' => "domains#public_html", :as => 'public'

Two variations on Ruby array#flatten

Implement Ruby’s flatten method for an Array (without taking any peaks at the source!). Probably not the hardest thing you’ll ever have to do, but there are many ways to do it… Jon and I each take a blind stab at it. Here’s our effort:

Mike’s variation

def mikes_flatten arr, level = nil
  result = []
  arr.each do |elem|
    recursive_flatten(result, elem,level,0)
  end
  result
end
 
def recursive_flatten(result, elem,level,current_level)
  if elem.is_a?(Array)
    elem.each do |el|
      if level.nil? || current_level < level
        recursive_flatten(result, el,level,current_level+1)
      else
        result << el
      end
    end
  else
    result << elem
  end
  result
end

Jon’s variation

def flatten values, level=-1
  flat = []
  values.each do |value|
    if level != 0 && value.kind_of?(Array)
      flat.concat(flatten(value, level-1))
    else
      flat << value
    end
  end
  flat
end

Perf different can be seen by Jon’s benchmark code (flatten.rb):

#!/usr/bin/ruby
require 'benchmark'
 
# Insert flatten methods here
 
def random_value
  if rand(3) < 1
    (rand(5)+1).times.map { |i| random_value }
  else
    rand(10000)
  end
end
 
VALUE = 100.times.map { |i| random_value}
ITERATIONS = 1000
 
Benchmark.bm do |b|
  puts "Iterations: #{ITERATIONS}"
  b.report("Mikes version") do
    ITERATIONS.times { |i| mikes_flatten(VALUE)}
  end
  b.report("Jons version") do
    ITERATIONS.times { |i| flatten(VALUE)}
  end
end

Jon’s is pretty succinct. When I first went about writing things out I was going for the “get it to work.” Either way, I don’t see a huge performance difference… They toggle back and forth by about a half a second.

[13:57:11 miker@laughwhat-lm ~/Downloads] $ ruby flatten.rb
      user     system      total        real
Iterations: 10000
Mikes version  2.920000   0.010000   2.930000 (  2.933274)
Jons version  2.990000   0.000000   2.990000 (  3.017929)
 
[13:57:25 miker@laughwhat-lm ~/Downloads] $ ruby flatten.rb
      user     system      total        real
Iterations: 10000
Mikes version  3.010000   0.010000   3.020000 (  3.030987)
Jons version  2.980000   0.010000   2.990000 (  2.999335)
 
[13:57:34 miker@laughwhat-lm ~/Downloads] $ ruby flatten.rb
      user     system      total        real
Iterations: 100000
Mikes version 26.860000   0.050000  26.910000 ( 26.973855)
Jons version 24.050000   0.050000  24.100000 ( 24.126557)
 
[13:58:34 miker@laughwhat-lm ~/Downloads] $ ruby flatten.rb
      user     system      total        real
Iterations: 100000
Mikes version 24.120000   0.050000  24.170000 ( 24.201227)
Jons version 25.080000   0.050000  25.130000 ( 25.196811)

Write your own and submit as a comment. Let’s see some other ways to do this :)