Class Objects from Strings
Or "Let the code write the code".
One of the beauties of Rails is that the "convention over configuration" mandate means that not just program execution but program implementation are extremely predictable. This is very handy when you'd prefer to have your code write the code, as I needed to this afternoon when I wanted to call the same function on a bunch of different classes who's names were available for the operation as an array of strings.
I first started out by spending far too much time mucking around with eval() but that felt kludgy and I've never liked using eval() in any language - I'm naturally gun-shy when it comes to arbitrary code execution. I may know all the code paths into that point today but what about six months from now? Will I always remember never to pass user data through there accidentally?
A little more reading of the Kernel module and the Module class revealed a much cooler and ultimately much simpler way to implement the same functionality: const_get().
In a nutshell:
-
begin
-
the_obj = Kernel.const_get( ( activity.model_name ).camelcase )
-
activity_events = the_obj.find( :all )
-
rescue
-
the_obj = nil
-
end
Much nicer but still not as nice as I'd like since I've had to wrap it in the begin / rescue block. For reasons unexplained const_defined? always returns false when used in here.
Note: Some googling afterwards showed up this very nice example by Matt Biddulph in which he used const_get() to walk the ActiveRecord models and create OmniGraffle diagrams of their relationships. That's a nice mash-up.
chris on March 15th 2007 in /dev/rails, /dev/ruby
