Looking for inverse of base_class (or other elegant solution

Wondering if any of the AR experts out there can tell me if there’s an
inverse to base_class, i.e. what subclasses, if any a class has. Some of
the classes I’m dealing with use STI. I could check to see if there’s a
type column, and then query that column to get the subclass names,
but… eeeurgh! There’s got to be a better way.

Tx
CT

Out of curiosity, what drives this need of yours?

Chris T wrote:

Wondering if any of the AR experts out there can tell me if there’s an
inverse to base_class, i.e. what subclasses, if any a class has. Some
of the classes I’m dealing with use STI. I could check to see if
there’s a type column, and then query that column to get the subclass
names, but… eeeurgh! There’s got to be a better way.

Tx
CT

Just to answer my own post, have found a solution, in case anyone else
needs it. There’s an undocumented method in ActiveSupport called
subclasses_of(class) that returns an array of the subclasses of a class
if there are any; an empty array otherwise. It’s a method of Object, so
you just call it straight without a receiver, e.g. @subclasses =
subclasses_of(MainClass).
Obviously as it’s not in the public API there’s no guarantee that it
won’t changed, but, hey, that’s what we’ve got tests for, isn’t it?

Hope this helps someone else…
CT

When you’re looping through a bunch of models, or sharing templates (and
actions) across models, some of which are vanilla classes, some of which
are base classes for STI subclasses, you need to be able to determine
programmatically whether you are dealing with a vanilla class (in which
case no prob), or an STI base-class, in which case what you need is the
subclasses.

It’s complicated a bit more (or rather simplified), because I’ve got a
RESTified controller per classes, each of which inherits from a
MasterController. The MasterController defines all the actions ( the
usual index, show, new, create, edit, update and destroy) and views
(although they call in class-specific partials), which makes the whole
thing very nice, clean, simple and very DRY.

Works great now I’ve figured out the subclasses stuff.

On 9/23/06, Chris T [email protected] wrote:

MasterController. The MasterController defines all the actions ( the
usual index, show, new, create, edit, update and destroy) and views
(although they call in class-specific partials), which makes the whole
thing very nice, clean, simple and very DRY.

Works great now I’ve figured out the subclasses stuff.

This will fail if the model class hasn’t been loaded. However, your
class-per-controller setup would permit something like
def model_class
self.class.name.sub(/Controller$/, ‘’).constantize
end
helper_method :model_class

jeremy

Jeremy K. wrote:

case no prob), or an STI base-class, in which case what you need
thing very nice, clean, simple and very DRY.

jeremy

Aren’t all the model classes load when the app starts? Actually, though,
I can improve things using your code about (though have to singularize
the names, as the controller names are plural versions of the model
names). I’d got a simple model_name method defined in each subcontroller
to define the model name, but you’re right, I could DRY it up further
and just infer this from the controller name in the MasterController.
Thanks for the tip.
CT

On Sep 23, 2006, at 12:39 PM, Chris T wrote:

CT
won’t changed, but, hey, that’s what we’ve got tests for, isn’t it?

Hope this helps someone else…
CT

Hey Chris-

Yeah subclasses_of will work for what you want but the ugly db query

might be faster. subclasses_of uses ObjectSpace to iterate over all
in memory objects and find the subclasses of the class you passed in
which can be very expensive if you have a lot of objects in
ObjectSpace(which rails does). It woudl be worth testing for but if
it won’t be used a lot in your app the by all means use the
subclasses_of

-Ezra

On 9/24/06, Chris T [email protected] wrote:

Jeremy K. wrote:

This will fail if the model class hasn’t been loaded. However, your
class-per-controller setup would permit something like
def model_class
self.class.name.sub(/Controller$/, ‘’).constantize
end
helper_method :model_class

Aren’t all the model classes load when the app starts?

Model classes are loaded when first referenced.

Actually, though,

I can improve things using your code about (though have to singularize
the names, as the controller names are plural versions of the model
names). I’d got a simple model_name method defined in each subcontroller
to define the model name, but you’re right, I could DRY it up further
and just infer this from the controller name in the MasterController.

Cool.
jeremy

On 9/24/06, Chris T [email protected] wrote:

I can improve things using your code about (though have to singularize
the names, as the controller names are plural versions of the model
names). I’d got a simple model_name method defined in each subcontroller
to define the model name, but you’re right, I could DRY it up further
and just infer this from the controller name in the MasterController.

I’ve been playing with what I think is some really fun stuff in that
vein for some weeks now. I have most of it bundled in a plugin called
resourcey_utils which you can find here:
http://sethrasmussen.com/svn/rails/plugins

There are some handy before_filters you can use with these same
assumptions we’re discussing to prepare a new resource instance, or
collection, etc. They are pretty generic, but like I say, fun and onto
something, methinks. I’m sure I’ll enhance it as time goes on. Using
these conventions, I’ve whittled a resource crud controller down to
something like this:

class BlogPostTypesController < ApplicationController
before_filter :new_resource, :only => %w(new create)
before_filter :find_resource, :only => %w(edit update destroy)
before_filter :paginate_resource, :only => :index

def create
if create_resource
redirect_back_or_default(blog_post_types_url)
else
render :action => :new
end
end

def edit
render :action => ‘new’
end
def update
if update_resource
redirect_back_or_default(blog_post_types_url)
else
render :action => ‘edit’
end
end

def delete
destroy_resource
redirect_back_or_default(blog_post_types_url)
end
end

If your controller could stay that generic, you could even abstract all
of those remaining methods into one or two class level calls or perhaps
something that is defined dynamically. I’ll probably work on adding
that, even if just for fun, in the near future. :slight_smile: I am thinking about
creating some class methods to wrap before filters that create and fine
a resource for the appropriate cruddy actions, too, though this is
another case where standardizing a slightly less assuming approach
might be good.

All in all, making certain assumptions when you can definitely kicks
ass and makes for clean code that feels like a warm hug to read.

Seth Thomas R. wrote:

—snip-----

All in all, making certain assumptions when you can definitely kicks
ass and makes for clean code that feels like a warm hug to read.

+1 for that. Coming from a non-programming background, it’s prob taking
me a while to get there, but I’m enjoying the ride. I’m finding the REST
stuff is forcing me to think more structurally and therefore write
cleaner, better code.

Ezra Z. wrote:

names, but… eeeurgh! There’s got to be a better way.
Object, so
Hey Chris-
-Ezra

Thanks Ezra, I’ll bear that in mind. At the moment I’m only using it for
new and edit, which isn’t a prob, but was thinking of using it for some
of the main pages too. Hmm – maybe need to re-think that. Don’t want to
prematurely optimise, but…

Actually, thinking about it, the app class structure isn’t going to
change once the app’s been started, and when it does change, (in
production at least), the app will be restarted. So maybe I could
generate the class structure when the app’s first run and bung it in a
constant. Makes sense?

Cheers
CT
p.s. Got a rough ETA on the book. About to enter the world of
deployment. Scary stuff!