Thursday, April 29, 2010

Bug with BigDecimal in Ruby 1.8.7 (patchlevel 173)

got out my brand new iMac today, and when I checked out my project, I had a bunch of tests failing. I thought I might have checked out an old version, but no everything was current and passing on my old dev machine. It wasn't in in my code. It wasn't even in rails. It was a problem with Ruby 1.8.7 (patchlevel 173). After hours of digging, behold the following console output in irb:


>> require 'bigdecimal'
=> true
>> BigDecimal.new(103123.98.to_s).to_f
=> 103123.98
>> BigDecimal.new(100123.98.to_s).to_f
=> 101239.8

Strangely enough, if you have a "0" as the fourth digit to the left from the decimal point when you build a big decimal object, it cuts it out. I have no idea why this is. I don't have time to investigate it. But I do know it doesn't happen with ruby 1.8.6, which is what I'm running in production, so for the moment it's not a real problem for me (except I had to change all my tests that had a 0 in that decimal place temporarily while I sort out bringing an older version of ruby onto my machine).

*sigh*

RMagick on OS X Snow Leopard

Just got a new iMac today, so I'm trying to get my project up and running on it. Things were going well until I got to RMagick. I always forget what a pain in the ass that gem is. I was lucky this time, after a little blog surfing, to find a great post by "hocuspokus" that provides some excellent help in the form of a shell script you can run to make it all happen (NOTE: you must have XCode developer tools already installed, it's on your Mac OS X Installation DVD). In the interest of giving credit to the right person, I'm not going to link directly to that script, but am instead just going to give a little link-love to the blog of the guy who made my day so much better when I found his website:

CLICK HERE TO GO TO THE HOCUSPOKUS BLOG SO THAT YOU CAN STOP TROLLING AROUND THE INTERTUBES TRYING TO GET THAT DAMN GEM INSTALLED ON YOUR NEW MAC!

Sunday, April 25, 2010

Getting my feet wet with Clojure

For the next few weeks, I'll be participating in the "Clojure 101" class at Ruby Learning. I don't have any plans to switch over from Rails as my primary platform in the near future, but I have a soft spot for the ol' JVM and an incomplete knowledge of functional languages, so I'm excited to have something of a diversion.

If you're interested in benefiting from my experience, I'm putting my notes/examples/exercises/experiments on my Github Account, and I'll continue to update it as a convenient place to store all my new knowledge (god knows my head's out of room).

Friday, April 23, 2010

Rails has_many scoping and database indexes

If you are a good rails coder, than you probably form your associations like this:



class Parent < ActiveRecord::Base
  has_many :children
end

class Child < ActiveRecord::Base
  belongs_to :parent
end

Which is correct. Then, to keep things looking pretty, when you want a scoped subset of a given parent's children, you probably write something like this



class Parent < ActiveRecord::Base
  has_many :children
end

class Child < ActiveRecord::Base
  belongs_to :parent
  named_scope :who_can_drive,:conditions=>"age >= 16"
end

parent = Parent.first
children = parent.children.who_can_drive


Which is well and good. Except when you care about performance. You see, I did something like this in my production application. Both fields on the child model are indexed (the foreign key, and the field used for searching by), but guess which one gets used first? If you know your named scopes, you know that in practice the named scope that is APPLIED LAST in the chain is used first in the query, and that's the one MySQL decided to use as the primary index.

Now if a parent has 2 or 3 children, but it's in a table of 15,000,000 kids between the ages of 14 and 21, which index do you think will produce the smaller set to scan? The one that narrows it down to only the 2 or 3 children of that parent and then checks their age, or the one that narrows it down to the 7 million children over the age of 16 and then checks their parent?

So to keep my server from crashing and burning, I've started writing my code like this:



class Parent < ActiveRecord::Base
  has_many :children
end

class Child < ActiveRecord::Base
  belongs_to :parent
  named_scope :who_can_drive,:conditions=>"age >= 16"
  named_scope :belonging_to,lambda{|parent| {:conditions=>{:parent_id=>parent.id}}}
end

parent = Parent.first
children = Child.who_can_drive.belonging_to(parent)


I don't like it, but it sure improved my scores on my newrelic monitoring graphs. Anybody have a more elegant solution to this problem?