Explain ActiveRecord queries in Rails console
May 15th, 2012I 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)
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)
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.
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!
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.
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.
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.
–
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| ...
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.
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…
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