Fixing Class Hierarchy In STI Under Development Mode

If you’re running your application in development mode, you may be frustrated when ActiveRecord seems to ignore the class hierarchy in your models, not loading any Apple objects when you call TreeFruit.find(:all). Blame this on the lazy class loading that development mode works with. You can avoid the problem at the cost of a few lines of code that explicitly declare your hierarchy without changing behavior in production mode, just make sure you do it correctly or you’ll end up loading Figs when you try loading Bananas (forgive my running with the silly fruit example). More after the fold…

Declaring Children at Each Level

Without eager loading, ActiveRecord won’t have the entire hierarchy mapped, and so you’ll have to do it explicitly, but simply declaring children at the top, in the example below, isn’t enough.

# This won't work
class TreeFruit < ActiveRecord::Base
  def self.subclasses
    [Apple, Pear] 
  end
end

class Apple < TreeFruit
end

class Pear < TreeFruit
end

Setting the subclasses manually gets inherited with everything else, however, and so in the above example loading Apples will also load Pears, and any other subclasses defined in the array at the top. You have to follow through and define subclasses at each level, even the leaf nodes.

# This works
class TreeFruit < ActiveRecord::Base
  def self.subclasses
    [Apple, RedDelicious, Pear] 
  end
end

class Apple < TreeFruit
  def self.subclasses
    [RedDelicious] 
  end
end

class RedDelicious < Apple
  def self.subclasses; []; end
end

class Pear < TreeFruit
  def self.subclasses; []; end
end

Rails Developers Get Wet (SFW)

ELC developers (and friend) headed to the town of Maupin, Oregon to engage in some heavy field testing of our newest product, “Ruby on Raft.” Overall the results were promising, even amidst inflated expectations, and we feel that it will stay afloat in the strong current of competition. Video and pictures after the jump.

While I didn’t make it in to any of the pictures (being the one taking them), you can get a shot of my feet as I intentionally and very much on-purpose get launched in to the water during our first rapid.

Victor 'He Almost Died' ChristensenJonathan 'Cabin Boy' SiegelMax 'Elvis' MurphyJonathan 'Walking on the Sun' SiegelMax, Jackson, Nick 'Fresh Mex' Aimes, and Victor

Manually Encoding Hashes and Arrays in a URL

I wasn’t able to find any examples of how rails expects arrays and hashes to be encoded in a url parameter string, which can sometimes be useful (and in the case of ActionView::Helpers::PrototypeHelper.remote_function before rails 2.3.2, entirely necessary). The information lies inside of ActionController::UrlEncodedPairParser.

ActionView::Helpers::PrototypeHelper.remote_function was problematic before rails 2.3.2 because any ‘&’ in the string returned by your named route helper (because you passed more than one parameter) was escaped as ‘&’. Rails 2.3.2 can parse ‘&’ in the url, but earlier versions couldn’t. One solution was to encode the parameter portion of the url by hand.

ActionController::UrlEncodedPairParser.post_key_check explains how rails decodes arrays and hashes from a parameter string:

‘a[]=b’ yields an array, params[:a] == [‘b’]

Multiple assignments yield multiple values in the array:
‘a[]=b&a[]=c’ yields params[:a] == [‘a’, ‘b’]

‘a[b]=c’ yields a hash, params[:a] == {‘b’ => ‘c’}

Putting it together, an array of hashes would look like this:
‘hashes[][key]=value1&hashes[][key]=value2’

Your STI Broke My Sphinx

If you’re using Ultrasphinx in your rails application and you have models using ActiveRecord support for Single Table Inheritance, it might not work they way you;d like. Actually it will break.

# == Schema Information
#
# Table name: fruits
#
#  id              :integer(4)      not null, primary key
#  type           :string(255)
#  size           :integer(4)

class Apple < Fruit
  is_indexed :fields => ['size']
end

If you try to run an Ultrasphinx call with the above definition, it will search an index that was built from the entire fruits table, returning ID’s that will raise an ActiveRecord::RecordNotFound exception when put through Apple.find(). To fix it, use the conditions argument to change the sql query that sphinx uses to build its index.

class Apple < Fruit
  is_indexed :fields => ['size'], :conditions => "fruits.type = 'Apple'"
end

Sti_sphinx

Agile sighting in LAX

Well…sort of an agile sighting…I mean, not really but sort of 😉

Scrum_shirt