A couple of random Rails tips
Posted by rick Wed, 03 Jan 2007 00:07:00 GMT
UPDATE: I edited the autotest hook to (1) fix a bug, and (2) to make it more readable (not sure if I succeeded, but worth a shot).
I figured out a couple of things that were useful enough to me that I thought I’d share.
First off, if you’re a big user of autotest (and if you’re not, you might oughta should be), and you’re working on a really large application, maybe you’ll find this useful:
Drop this in your ~/.autotest file:
Autotest.send(:alias_method, :real_find_files, :find_files)
Autotest.send(:define_method, :find_files) do |*args|
real_find_files.select do |k,v|
(ENV['AUTOTEST'] and ! ENV['AUTOTEST'].empty?) ?
Regexp.new(ENV['AUTOTEST']).match(k) : true
end
end
and then you can do stuff like:
% AUTOTEST='users' autotest # run all tests with 'users' in the name
% AUTOTEST='digital.*cont' autotest # run all the digital signaturing functional tests
% AUTOTEST='party|digital' autotest # run all tests for parties or digital signaturing
This allows you to focus in on a small area of concern and still get the rapid feedback autotest gives you. Be sure to periodically run your entire test suite to make sure you’re not missing action-at-a-distance errors.
The other tip is a purely Rails tip. If you’re ever used ActiveRecord’s polymorphic associations then you may have run into a situation where you want many many many things to be able to be on the other (has_many) end of the polypmorphic association. I ran into this while doing work with digital signatures: I want to be able to associate a signature with almost any model object in my system. I should be able to retrieve the signatures (if any) for an object by just saying “object.signatures”.
This would normally require a “has_many :signatures, :as => signable” in every signable class in the system. Maybe reasonable, but if I were to forget to add the has_many to a class signaturing would stop working. It’s actually worse in my case since the signing algorithm can sign a web of related objects, so forgetting the has_many in one class would result in failures in related but not identical classes.
I decided to add functionality to have this happen automatically. At first I tried just opening ActiveRecord::Base and adding the call, which doesn’t put the call in the right scope for the subclasses (as don’t a variety of other AR::Base hacks I tried). I realized at some point that I needed to use Ruby’s “inherited” method to get the subclass at the right time, but AR::Base already uses inherited for other nefarious purposes. It turns out, this is the incantation that works:
class ActiveRecord::Base
def self.inherited_with_signaturing(subclass)
self.inherited_without_signaturing(subclass)
subclass.send(:has_many, :signatures, :class_name => 'DigitalSigDigest', :as => :signable) unless subclass.name =~ /^DigitalSig/
end
class << self
alias_method_chain :inherited, :signaturing
end
end
As you’ll notice, my signaturing model is actually DigitalSigDigest. Also, I have other DigitalSig-something classes lying around that are part of the signaturing library, and using inherited this way allows me to actually conditionally include/exclude which classes get the signaturing has_many relationship. That’s cooler than I expected. Chalk up another one for Ruby.
By the way, you’re probably also going to be interested in this ticket if you’ve got STI classes with polymorphic stuff linked to them.

