Alex Chaffee's blog
Collapsing Migrations
(6:30 pm: updated to use mysqldump) (12/14/07: updated to remove db:reset since the Rails 2.0 version now does something different.) (12/15/07: updated to not set ENV['RAILS_ENV'] since that gets passed down to child processes)
There was an old hacker who lived in a shoe; she had so many migrations she didn't know what to do. Every time her build ran clean, she spent a whole minute staring at the screen.
Fortunately, she read this blog post and now her db:setup task is so fast she's started building multiple test environments so she can run tests in parallel!
rake query_trace
QueryTrace is a great Rails plugin (which I learned about from ErrTheBlog) for pinpointing where in your Rails application that slow query is running. Once you have it installed, your logs won't just tell you that you have a problem, they will pinpoint the exact location of that problem for you. This is invaluable when doing load & performance testing or just trying to understand what the hell ActiveRecord is doing.
Unfortunately, even though it only logs query traces in DEBUG log mode, it still clutters up your test and development logs, and actually slows things down a bit too. So you don't want to leave it in your project's vendor/plugins directory after you're done using it. So I wrote a pair of rake tasks to enable and disable it.
rake query_trace:on # Enables the query_trace plugin. Must restart server to take effect.
rake query_trace:off # Disables the query_trace plugin. Must restart server to take effect.
The "on" task actually checks out the plugin from query_trace's subversion repository, makes a tarball in vendor/query_cache.tar.gz, then leaves the tarball around so it doesn't have to keep going to the network all the time. You can even check the tarball in to your project and it'll never go to the query_trace repository again. The "off" task just removes the whole vendor/plugins/query_cache directory.
namespace :query_trace do
desc "Enables the query_trace plugin. Must restart server to take effect."
task :on => :environment do
unless File.exist?("#{RAILS_ROOT}/vendor/query_trace.tar.gz")
Dir.chdir("#{RAILS_ROOT}/vendor") do
url = "https://terralien.devguard.com/svn/projects/plugins/query_trace"
puts "Loading query_trace from #{url}..."
system "svn co #{url} query_trace"
system "tar zcf query_trace.tar.gz --exclude=.svn query_trace"
FileUtils.rm_rf("query_trace")
end
end
Dir.chdir("#{RAILS_ROOT}/vendor/plugins") do
system "tar zxf ../query_trace.tar.gz query_trace"
end
puts "QueryTrace plugin enabled. Must restart server to take effect."
end
desc "Disables the query_trace plugin. Must restart server to take effect."
task :off => :environment do
FileUtils.rm_rf("#{RAILS_ROOT}/vendor/plugins/query_trace")
puts "QueryTrace plugin disabled. Must restart server to take effect."
end
end
dot.rake
[Update: 10/15/07 - incorporated changes by David Vrensk (and a few more from me). Now it merges in associations into the arc, and also deals with inheritance (e.g. STI).]
While googling for articles on Rails associations, I happened upon this gem of a script by Matt Biddulph. I loved it so much I made it a rake task! Once you install GraphViz like this:
sudo port install graphviz
and put dot.rake in your lib/tasks directory, then running this:
rake dot
produces diagrams like this:

And you can also import the DOT source into OmniGraffle for further editing, like this:
open -a "OmniGraffle" model.dot
doing it again and again
Here's an RSpec trick I discovered yesterday. Sometimes when you're writing a test you want to loop over some precondition data. But if you do a loop inside your test (or spec), then all the cases will be subsumed in a single test method (or "it" block). This means you'll have the following problems:
- The first case to fail will cause the rest of the cases not to run. It'd be nice to see them all in a single test run.
- You won't take advantage of RSpec's cool self-documenting trick of labeling each it block with a full description of the failure, and it'll be harder to debug which case failed.
- If you're calling into Rails (e.g. in a View spec), you'll only be able to call certain methods -- especially
render-- once per test method. That means that you simply can't use a loop inside a method to collapse redundant tests into a single block.
Ruby to the rescue! Instead of looping inside your it block, loop outside your it block.
Lovely Demeter, Meter Maid
Wes and Parker pointed us to this article:
Misunderstanding the Law of Demeter by Dan Manges
which is a very nice discussion of the "law" (actually just a suggestion, but a very strong one) that encourages your objects, like small children, not to talk to strangers. Some people seem uneasy with the LoD since it requires them to refactor their objects to have proxy methods all over them. Instead of Paperboy calling customer.wallet.cash you have to put an extra method on Customer -- either cash (attribute delegation -- check out Forwardable in Rails btw) or pay (behavior delegation). But these proxy methods are not clutter, they're the essence of encapsulation. Do not fear encapsulation. Fear is the mind killer.
Anyway, Dan does a great job explaining this concept, until the very end of the article, when he totally chickens out.
Rails Filter Parameter Logging
Q: How do you keep passwords from appearing in plain text in your Rails log file?
filter_parameter_logging
=> Does nothing, just slows the logging process down
filter_parameter_logging :password
=> replaces the value to all keys matching /password/i with "[FILTERED]"
filter_parameter_logging :foo, "bar"
=> replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
=> reverses the value to all keys matching /secret/i
filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
=> reverses the value to all keys matching /secret/i, and
replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
(Note that :password matches password_confirm too.)
Rails Conference Links
(Blabbers who were at the conference, feel free to add your links to this post.)
- Alex's RailsConf2007 Flickr set
- railsconf2007 Flickr tag (notice all the band pix :-) )
- Parker's Flickr Set
- Martin Fowler's bliki post on RailsConf
- Tim Bray on the band







