deferred until inspiration hits

Helpful error messages when active record objects fail validation (in tests)

Posted by Chris Roos Wed, 02 Aug 2006 13:47:00

I posted a while back about displaying the reasons for an active record model failing validation.

I knew the code was hacky and nasty but didn’t realise quite how bad until I noticed how simply (1 line) the same thing was implemented in Rails 1.1 (and above).

Although it’s only useful for people still on Rails 1.0, I made a quick plugin that backports this change. I don’t really want to put it in my subversion repository, so have just pasted the necessary code below.

# File init.rb
require File.dirname(__FILE__) + '/lib/record_invalid'
# File record_invalid.rb
module ActiveRecord

  class RecordInvalid < ActiveRecordError
    def initialize(record)
      @record = record
      super("Validation failed: #{@record.errors.full_messages.join(", ")}")
    end
  end

end

To create a plugin from this, create the following structure in your rails_app/vendor/plugins directory.

active_record_validation_error/
|
|--init.rb (copy contents of code above)
|
|--lib/
   |
   |--record_invalid.rb (copy content of code above)

Tags , , , ,

Textmate command to display Active Record column attributes

Posted by Chris Roos Fri, 14 Jul 2006 08:18:00

I find myself constantly visiting either the console or the mysql command line to check out the attributes (columns) of active record objects.

I know there is a plugin by Dave Thomas that places the table structure within the model code itself. To be honest I’ve never tried this and it might well suffice (although I’m not 100% convinced I like the idea).

Anyhoo, I just spent some time whilst on the train hacking together a basic textmate command that displays a tooltip containing the table structure. It’s very basic (though you wouldn’t have thought it based on the amount of time it took me together1); but seems to work ok.

The code is below. You’ll need to add a ruby command in the ruby textmate bundle, setting the intput to ‘selected text’ or ‘nothing’, the output to ‘show as tooltip’ and preferably a hotkey that isn’t one of the ones you use every day (however tempting that is).

#! /usr/local/bin/ruby

project = ENV['TM_PROJECT_DIRECTORY']
word = ENV['TM_CURRENT_WORD']

require "#{project}/config/boot"
require "#{project}/config/environment"

klass = Object.const_get(word) rescue nil
if klass and klass.class == Class and klass.ancestors.include?(ActiveRecord::Base)
  columns = klass.columns_hash

  data = []
  data += [%w[column primary sql_type default]]
  data += [%w[------ ------- -------- -------]]
  data += columns.collect { |col, attrs| [col, attrs.primary.to_s, attrs.sql_type.to_s, attrs.default.to_s] }

  STDOUT << data.inject('') do |output, array| 
    output + array.inject('') { |row_str, value| row_str + value.ljust(20) } + "\n"
  end
elsif klass and klass.class == Class and not klass.ancestors.include?(ActiveRecord::Base)
  STDOUT << "#{word} is not an Active Record derived class"
else
  STDOUT << "#{word} was not recognised as a class"
end

It relies on you having your entire rails project (the folder right above app, config, script etc) open in textmate (in order to find the config files). With that, just click on the name of an active record class (it has to be the actual class name at present, it’d be cool if it also worked based on the class definition you are currently in too) and hit your hotkey of choice (best to use the one you assigned to this command). Hey presto, a tooltip containing your table structure.

One odd thing I’ve noticed is that it never recognises standard class constants. It should display ‘this is not an active record derived class’ but instead always displays ‘was not recognised as a class’. Oh well.

Anyone find this remotely useful or want to finish off what I’ve started?

[1] I spent ages trying to develop within the textmate bundle editor before realising it’d be a helluva lot quicker and easier to develop in textmate proper. Hmmm.

Tags , , , ,

Using in memory Active Record objects with associations for testing

Posted by Chris Roos Wed, 12 Jul 2006 01:23:00

Hitting the database in testing is bad.

Something that I’ve found relatively useful at work is to use real Active Record objects without any persistence (basically use AR#new and not AR#save[!] or AR#create[!]). When using standard techniques to create the association objects in memory you only get one side of the association at a time. Consider the following.

class Person < ActiveRecord::Base
  has_many :addresses
end
class Address < ActiveRecord::Base
  belongs_to :person
end

# One sided relationship with parent getting access to child
chris = Person.new
home = chris.addresses.build

chris.addresses.first
=> #<home>
home.person
=> nil

# One sided relationship with child getting access to parent
home = Address.new
chris = home.build_person

chris.addresses
=> []
home.person
=> #<chris>

# The example above that creates the address first could also have been written as.
# chris = Person.new
# home = Address.new(:person => chris)

You can see that in each case, only one side of the relationship has access to the other. If we were persisting the objects then the relationship would be two way via a database lookup. We can get a two way relationship in memory; although it has a certain duplication smell about it. Assuming the same models as above, we can amend the above examples like so.

# First example
chris = Person.new
home = chris.addresses.build(:person => chris)

chris.addresses.first
=> #<home>
home.person
=> #<chris>

# Second example
home = Address.new
chris = home.build_person(:addresses => [home])

home.person
=> #<chris>
chris.addresses.first
=> #<home>

I’ve occasionally used this in place of stubbing methods but am still not 100% convinced of the definite benefits one way or another. I do have some definite disadvantages of stubbing methods (nothing exciting, they’ve almost certainly been noted by many others in the past) which I’ll note down at a later date.

Tags , , , ,