The Worst Rails Code

Jun 07, 2008

I just came back from RailsConf 2008 in Portland. This year was great. There were a lot of exciting developments to talk about, like MagLev, SkyNet, mod_rails and Rails 2.1.

The talks seemed better this year as well. The one I was most looking forward to was from Obie Fernandez, who wrote The Rails Way, published last fall. I can easily say this is the best Rails book published to date (sorry, Pragmatic). It’s packed with useful information, best practices, and real-world code. Obie’s excellent writing style along with contributions from numerous Rails coders make it a great read too. My copy is already showing wear. And at 900+ pages, it’s like a phone book.

Obie’s talk was given to a packed room, despite being scheduled on Sunday morning at 9am. The title of the talk, “The Worst Rails Code You’ve Ever Seen (and how not to write it yourself)”, discouraged my friends from attending (“sounds depressing”, one said). During the first lightning round, we had seen some pretty bad code proudly presented (to which Ryan Davis publicly expressed his horror).

But the talk was worth getting up for. Through a series of real-world examples, Obie (and co-presenter Rein Henrichs) showed the audience just how bad Rails coding can get. Some of the code was truly appalling, like a 1200+ line app in a single controller (no, really). Other examples looked, well, kind of familiar. Having been involved in several Rails projects myself since 2005, I’ve seen (and written) my share of bad code.

Geodistance Searching with Ultrasphinx 4 Comments

May 01, 2008

I’m happy to annouce a patch for Ultrasphinx that enables access to the geographical distance searching in the Sphinx full-text search engine.

Syntactical Sugar

Apr 29, 2008

On recent rails projects, I found myself clinging to a few useful helpers and additions. Here’s a few.

hide_unless

Often in views, I find I want to hide a particular div or element, but only if certain conditions are met. An ajax call might later reveal it, or replace the contents of the div with something.

 def hide_unless(condition)
    condition ? '' : 'display:none'
 end

In use:

<div id="edit_pane" style="<%= hide_unless(@story) %>"></div>

present?

Rails gives us .blank?, but I hate writing things like:

  <% if !@stories.blank? %>
    ... etc
  <% end %>

So, I add this as an extension in my projects:

class Object
  def present?
    !blank?
  end
end

And obviously it works on anything: arrays, hashes, nil, etc.

  <% if session[:setting].present? %>
   etc...
  <% end %>

UPDATE (29-Jun-2008): DHH just committed this to Edge Rails. I have no proof that I had anything to do with it, but I’ll pretend :)

user_owns_it

A common task is to check if the current user owns a particular resource.

  def user_owns_it(asset)
    asset.respond_to?(:created_by) and asset.created_by and current_user and asset.created_by.id == current_user.id
  end

This allows easy checking in views:

<% if user_owns_it(@post) %>
   link_to "Edit Your Post", edit_post_path(@post)
<% end %>

Please share if you have other interesting tidbits from your toolbox!

My .irbrc

Dec 23, 2007

Some collected recipes to make irb and script/console a bit nicer to use:

  • pretty printing (pp whatever)
  • enhanced tab completion
  • rails logging to console
  • saves command history between sessions
  • use readline extensions module

Tips were collected from posts by Dr. Nic, Toolman Tim and Dzone Snippets.

~/.irbrc

require 'pp'
require 'irb/completion'
ARGV.concat [ "--readline", "--prompt-mode", "simple" ]
IRB.conf[:AUTO_INDENT]=true

# load console_with_helpers if possible
script_console_running = ENV.include?('RAILS_ENV') && IRB.conf[:LOAD_MODULES] && IRB.conf[:LOAD_MODULES].include?('console_with_helpers')
rails_running = ENV.include?('RAILS_ENV') && !(IRB.conf[:LOAD_MODULES] && IRB.conf[:LOAD_MODULES].include?('console_with_helpers'))
irb_standalone_running = !script_console_running && !rails_running

# log Rails stuff to STDOUT
if script_console_running
  require 'logger'
  Object.const_set(:RAILS_DEFAULT_LOGGER, Logger.new(STDOUT))
end

# Keep command-line history between startups
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history" 

Update: my friend Joannou pointed out Utility Belt which looks pretty nice also.

Update 2 (a month later): Been using Utility Belt for a while and noticed some problems… it has a tendency to conflict with ActiveRecord validations and trigger bogus errors during callbacks. Also seems to destroy some of the init process with certain plugins like ActiveScaffold. Perhaps it’s too clever. I ended up rolling back to my old .irbc – YMMV.

Validating Fixtures

May 23, 2007

Fixtures Are Painful

I just got back from RailsConf 2007, it was a brain-expanding conference. I spent a lot of time talking to Rails coders about how they do testing and use fixtures. I saw some patterns emerge. Generally, people agree that fixtures are painful:

  • referencing ids in the fixtures is annoying and prone to error
  • the lack of a grouping mechanism makes selecting them harder
  • fixtures get out of date with model changes

I plan to do a few posts about fixtures in the next coming weeks, to share some of what I have learned. For now, I’ll focus on validation.

Fixtures Break

The project I’m currently working on has a large number of fixtures (over 100 models). It’s become really hard to manage them all. Over time, some fixtures busted, and it became hard to diagnose random problems in tests.

We are fortunate to be working with zenspider, he’s helping us get our tests, dev process and performance in better shape. I complained a lot about invalid fixtures, and how I longed for a Rake task that could identify the broken ones. He offered up this:

namespace :db do
  namespace :fixtures do
    task :validate => :environment do
      name_map = Hash.new { |h,k| h[k] = k }

      Dir.chdir("app/models") do
        map = `grep set_table_name *.rb`.gsub(/[:\'\"]+|set_table_name/, '').split
        Hash[*map].each do |file, name|
          name_map[name] = file.sub(/\.rb$/, '')
        end
      end

      Dir["test/fixtures/*.yml"].each do |fixture|
        fixture = name_map[File.basename(fixture, ".yml")]

        begin
          klass = fixture.classify.constantize
          klass.find(:all).each do |thing|
            unless thing.valid? then
              puts "#{fixture}: id ##{thing.id} is invalid:" 
              thing.errors.full_messages.each do |msg|
                puts "   - #{msg}" 
              end
            end
          end
        rescue => e
          puts "#{fixture}: skipping: #{e.message}" 
        end
      end
    end # validate
  end # fixtures
end # db

Put it in your project Rakefile, and you can then run:

$ rake db:fixtures:validate

You will get back a list of all the fixtures that are not valid, with the validation messages.

But what about edge cases? What about “bad” form data? DHH has declared that most folks want all fixtures loaded at the start of the tests. The data in fixtures does not have to pass model validation before it is loaded into the db.

After discussing this with a number of folks, I’m starting to believe:

  • All fixtures should be valid at all times
  • Fixtures should provide stuff required by your app to run tests (your admin user, default options, etc)
  • Edge cases should be created in tests, not fixtures
  • Test invalid data by loading a good fixture and changing it

Rake db:fixtures:validate is helpful for keeping them valid. I plan to use it whenever I do a migration, just to ensure that nothing got broken.

RailsConf 2007

May 16, 2007

Heading out to Portland tomorrow, I’m very excited. There are a whole lot of great presentations this year. Here’s what I plan to see.

Rake task to run a custom group of tests

Apr 16, 2007

I have not really been getting into blogging yet, obviously. It’s been several months since the most recent post. I’m in New York at the moment, getting ready to launch a rails web project. More details about that later.

For now, I just had to post something I did recently that was handy: Using rake to run a specific group of files.

There are some great built-in tasks provided by Rake. Let’s look at the testing-related ones (run ‘rake -T’ to see them all):

rake test:functionals               # Run the functional tests in test/functional
rake test:integration               # Run the integration tests in test/integration
rake test:plugins                   # Run the plugin tests in vendor/plugins/*/**/test (or specify with PLUGIN=name)
rake test:recent                    # Test recent changes
rake test:uncommitted               # Test changes since last checkin (only Subversion)
rake test:units                     # Run the unit tests in test/unit

These are all very useful. But on the site I’m currently working on, I wanted to run a set of tests that were related to a section of the web site: the web store. I wanted to be able to run a specific combination of unit, functional, and integration tests.

I looked at the source for the tasks that rails provides for rake. The testing tasks are defined in lib/tasks/testing.rake in the rails distribution. The code for the unit testing task, for example:

  desc "Run the unit tests in test/unit" 
  Rake::TestTask.new(:units => "db:test:prepare") do |t|
    t.libs << "test" 
    t.pattern = 'test/unit/**/*_test.rb'
    t.verbose = true
  end

The files are specified as a glob. But, I did not want to use a file pattern. I consulted the rake API docs and discovered the test_files= setter method of Rake::TestTask. Here’s what I ended up with:

namespace :test do
  tests = []
  tests << "test/integration/store_test.rb" 
  # models
  %w(product product_category product_categorization product_option product_option_value 
    line_item cart order shipment).each do |file|
      tests << "test/unit/#{file}_test.rb" 
  end
  # controllers
  %w(cart checkout store).each do |file|
    tests << "test/functional/#{file}_controller_test.rb" 
  end
  # admin controllers
  %w(products product_option_values product_options orders).each do |file|
    tests << "test/functional/admin/#{file}_controller_test.rb" 
  end
  Rake::TestTask.new(:store => "db:test:prepare") do |t|
    t.libs << "test" 
    t.test_files = tests
    t.verbose = true
  end
  Rake::Task['test:store'].comment = "Run the store-related tests" 
end

I saved this task in lib/tasks/store_tests.rake under my project directory. Now, I can do this:

$ rake test:store
(in ~/rails_project)
/opt/local/bin/ruby -Ilib:test "/opt/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader.rb" "test/integration/store_test.rb" "test/unit/product_test.rb" "test/unit/product_category_test.rb" "test/unit/product_categorization_test.rb"  [... etc ...]
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake/rake_test_loader
Started
....................................................................
Finished in 10.799886 seconds.

68 tests, 682 assertions, 0 failures, 0 errors

All the store tests are run as a group. This is a nice way to verify that things are working in the money-making part of the site.

However, I have to remember to update the task whenever I refactor or make additions. I’m thinking about symbolic links, now. Perhaps the tests could be grouped together in a directory (like test/groups/store) by making symbolic links to them in there. And, subversion deals with symlinks well…

First Post

Nov 07, 2006

Wow. This is where it all starts.

So, I’ve been thinking about a blog for a while now. I recently moved with my wife and daughter to Switzerland. Such a big life change, and friends left behind in New York City. Seems like a good time to start.

I just installed Mephisto, which is a Ruby on Rails application. So far, it seems pretty nice.