Explain ActiveRecord queries in Rails console

May 15th, 2012

I keep missing this in Google somehow, but if you want ActiveRecord to explain your queries in the console, do:

ActiveRecord::Base.logger = Logger.new(STDOUT)

via shime on StackOverflow

Destructive (fast) Ruby each

May 11th, 2012

As mentioned, if you have a loop that allocates a bunch of memory tied to an object, destroying the current object after each iteration can help save on memory. I found myself reusing this pattern, so I just extended Array:

class Array
  def destructive_each
    while item = shift
      yield(item)
    end
  end
end

It’s called “destructive” because after using it your array will be empty.

Simplify your conditional step definitions with should_unless

March 23rd, 2012

In cucumber, you often want to be able to use a step in both it’s positive and negative form. For example, in different universes I might want to ensure that “pigs can fly”, or that “pigs can not fly”. Typically I’ve either written two step matchers for this, or added an awkward conditional:

Then /^pigs can (not |)fly$/ do |negated|
  if negated.blank?
    Pig.new.should have_the_power_of_flight
  else
    Pig.new.should_not have_the_power_of_flight
  end
end

But today I decided to factor that out into a little helper method in my cucumber config:

# features/support/env.rb
class Object
  def should_unless(missing, matcher)
    missing.match(/not/) ? should_not(matcher) : should(matcher)
  end
end

This allows me to write my matcher much more simply:

Then /^pigs can (not |)fly$/ do |negated|
  Pig.new.should_unless negated, have_the_power_of_flight
end

So fresh and so DRY!

Memcache on Rails with Dalli not expiring

March 15th, 2012

This was a little bit of a stumper. In testing, when I tried to cache objects in Memcache with Dalli, by setting expires_in to, say, 5.seconds, the cache didn’t seem to expire.

After debugging into Dalli, I now see why:

# dalli-1.1.4/lib/active_support/cache/dalli_store.rb:131
if expires_in > 0 && !options[:raw]
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
  expires_in += 5.minutes
end

Dalli adds 5 minutes to the expires_in for all cache writes.

Using rescue to save on nested ifs

February 22nd, 2012
hash = {
  :a => {:one => 1},
  :b => {:two => 2}
}

I was wanting to write some code that would grab a value from a nested hash like the one above, without knowing whether any of the keys existed, or if even the hash existed. My immediate thought was just to use ifs:

def a1
  if hash && hash[:a]
    hash[:a][:one]
  end
end

That’s a little gnarly with repetition though. So I thought maybe I could just use a rescue:

def a1
  hash[:a][:one]
rescue
end

It certainly reads nicer, and explains the situation more clearly. But using exceptions like this smells a little dangerous. You don’t want to accidentally catch and ignore some other exception. But in this case, where the entire content of the method is just accessing hash values, it seems OK.

I wasn’t sure about performance though. So I wrote a little script to test the two strategies:

def rescuers
  something = {:twelve => 12}
  nothing = nil
  something[:twelve]
  nothing[:twelve]
rescue
end
 
def iffers
  something = {:twelve => 12}
  nothing = nil
  if something
    something[:twelve]
  end
  if nothing
    nothing[:twelve]
  end
end
 
start = Time.now
100000.times do
  rescuers
end
puts "rescuers took #{(Time.now - start)} seconds"
 
start = Time.now
100000.times do
  iffers
end
puts "iffers took #{(Time.now - start)} seconds"

Of course, this is hardly a “natural” benchmark. But it’s better than nothing.

It turns out, on my machine, the rescue strategy is about a factor of 10 slower than the conditional. That’s pretty damning, HOWEVER, you can still do 100,000 rescues in a second. So, unless I’m doing this thousands of time in a web request, it won’t really tip any important scales.

I’m going to go with the rescue for now, and see how I feel about it.

Shift is your friend

February 14th, 2012

This code¹:

crops.each do |c| 
  c.calculate_status(user)
end

takes 0.3 seconds to run. This code:

crops = crops.to_a 
while(c = crops.shift)
  c.calculate_status(user)
end

takes 0.00001 seconds to run. Using shift lets Ruby clear that junk out of memory as soon as you leave the current iteration of your while loop. Each makes you keep it around.

Be advised.

¹ The calculate_status method works looks up some dozens of activerecord objects from different tables and does various calculations amongst them.

Stupid Rails Tricks: Using find and find_all on ActiveRecord collections

February 5th, 2012

ActiveRecord collections are enumerable, but they override Enumerable’s find and find_all methods to hit the database. But the versions on Enumerable are totally different. They feed objects to a block and return the ones for which the block returns true. Sometimes that’s what you want.

I used to convert the collection to an array so I could use the Enumerable methods, but that is far from optimal in terms of memory use. Then I figured out Enumerable has the detect and select aliases which work the same way, and work on AR collections:

# Find all the broody chickens that weigh at least 5 lbs:
Chickens.broody.find(:first, :conditions => ["weight >= ?", 5])
 
# Find all the broody chickens whose favoriate food is snails:
Chickens.broody.detect do |chicken|
  chicken.meals.map(&:food).mode == "snail"
end
 
# Instead of having to do 
Chickens.broody.to_a.find_all do |chicken|
  ...

Stupid Ruby Tricks: Range to the end of an array

February 4th, 2012

Did you know that if you give an array a symbol as the second parameter of a range, and it will just go to the end of the array? Check it out:

array = [1,2,3,4]
array[2,:end] # [3,4]

Any symbol will do, but :end seems like a good choice.

Controller actions not running

December 28th, 2011

Every year or so I scratch my head for a half hour doing this…. I’m trying to debug something in my cucumber tests, and somehow code that I think must be running is not running. I insert breakpoints and they just never get hit. I slowly step up the call chain until I put a breakpoint at the top of the controller action, and it’s still not getting hit!

I check the routes. I check the paths. Everything seems fine. I’m supposed to be in that controller, on that action. What the heck!

And then, AHA! I’m getting stuck in a before_filter. Of course. Silly me.

And then I go another year before it happens again…

Minimal templating DSL in pure Ruby

December 12th, 2011

For whatever reason, I felt like working on my metaprogramming brain a little bit last night. So I implemented an as-simple-as-possible templating DSL in pure Ruby. Only 34 lines of code and lets you generate pretty much arbitrary HTML. It ends up being basically a shitty version of Markaby.

Here’s the code and an example:

class Tmpl
  def initialize(tag, *args, &block)
    @tag = tag
    @content = args.find {|a| a.instance_of? String}
    @attributes = args.find{|a| a.instance_of? Hash}
    self.instance_eval &block if block_given?
  end
 
  def to_html
    attr_string = " " << @attributes.map {|k,v| "#{k}=#{v.to_s.inspect}" }.join(" ") if @attributes
    "<#{@tag}#{attr_string}>#{@content}#{children.map &:to_html}</#{@tag}>"
  end
 
  def children
    @children ||= []
  end
 
  # Some of these are Kernel or Object methods or whatever that we need to explicitly override
  [:p, :select].each do |name|  
    define_method name do |*args, &block|
      send :method_missing, name, *args, &block
    end
  end
 
  def method_missing(tag, *args, &block)
    child = Tmpl.new(tag.to_s, *args, &block)
    children << child
    child
  end
 
  def self.method_missing(tag, *args, &block)
    Tmpl.new(tag.to_s, *args, &block)
  end
end
 
 
puts Tmpl.html {
  head do
    title "Hello, World!"
  end
  body do
    h1 "Hi", :class => "foo"
    p "This is an awesome thing. " do
      b "Hot "
      a "Sauce", :href => "/awesome"
    end
    select do
      option "Not me"
      option "There can be only one", :selected => true
    end
  end
}.to_html