STI Question


#1

Hi everyone,

I have 3 types of people (for now):

Staff
Faculty
Students

To break them up into classes, but keep them in the same People table,
I’ve broken them up like so (code and ‘ends’ snipped):

class Person < ActiveRecord::Base
class Employee < Person
class Staff < Employee
class Faculty < Employee
class Student < Employee

So, when I insert people, everything works fine. If I do a
Staff.find, I get only staff. Employee.find, only employees, etc.
Fantastic.

Now, say I couldn’t do Employee.find (and I probably can, but I’m
still curious), how could I do a Person.find if I only knew that
someone was an employee and not either Faculty or Staff without
resorting to :conditions => [“type = ‘Staff’ OR type = ‘Faculty’”]?

Thanks!

Sean


#2

On Wed, Feb 15, 2006 at 02:59:38PM -0500, Sean H. wrote:

Now, say I couldn’t do Employee.find (and I probably can, but I’m
still curious), how could I do a Person.find if I only knew that
someone was an employee and not either Faculty or Staff without
resorting to :conditions => [“type = ‘Staff’ OR type = ‘Faculty’”]?

You don’t. The point of STI is that those sorts of things are taken
care of
for you by running the #find at the appropriate level in the class
hierarchy.

  • Matt

#3

Well, what I was getting at (and didn’t–my bad) is that I won’t know
to do “Employee.find” because I don’t know what type of search is
coming in.

Assuming person_type is one of “Employee”, “Faculty”, “Staff”, etc,
I’m trying this:

@people = eval(person_type + ‘.find’ + ‘:all, :conditions => cond’)

This seems to work, except the conditions don’t come in correctly.
I’m using Ezra’s ez_where plugin to create the conditions, but I can’t
get the cond variable to work correctly in the eval. I end up with:

SELECT * FROM people WHERE (#Caboose::EZ::Condition:0x24da974) AND (
(people.type = ‘Employee’ ) )

So, maybe the issue is with how I’m using the plugin and not the find
itself.

Thanks everyone!

Sean


#4

Now, say I couldn’t do Employee.find (and I probably can, but I’m
still curious), how could I do a Person.find if I only knew that
someone was an employee and not either Faculty or Staff without
resorting to :conditions => [“type = ‘Staff’ OR type = ‘Faculty’”]?

Thanks!

Sean

What’s wrong with that?

Employee.find :all, :conditions => [“type IN (?)”, [‘Staff’, ‘Faculty’]]

Or if you’re doing that a lot:

class Employee < ActiveRecord::Base

Employee.find_all_by_types ‘Staff’, ‘Faculty’

def self.find_all_by_types(*types)
find :all, :conditions => [‘type IN (?)’, types]
end
end


Rick O.
http://techno-weenie.net


#5

Sean-

I would recommend doing it this way and avoiding eval. ez_where

conditions won’t work properly inside an eval like that.

person_type = “Employee”

@people = person_type.constantize.find :all, :conditions => cond
OR
@people = Object.const_get(person_type).find :all, :conditions => cond

Cheers-
-Ezra

On Feb 15, 2006, at 2:37 PM, Sean H. wrote:

I’m using Ezra’s ez_where plugin to create the conditions, but I can’t
Sean

find :all, :conditions => ['type IN (?)', types]

Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
removed_email_address@domain.invalid


#6

Oh and you might need to ad .to_sql on your cond object to make it work:

@people = person_type.constantize.find :all, :conditions => cond.to_sql

-Ezra

On Feb 15, 2006, at 2:37 PM, Sean H. wrote:

I’m using Ezra’s ez_where plugin to create the conditions, but I can’t
Sean

find :all, :conditions => ['type IN (?)', types]

Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
removed_email_address@domain.invalid


#7

Constantize? Constantize!

Ezra! I kiss you!


#8

Ok, so, constantize is working perfectly and helping me to replace a
lot of evals in other places.

My next step in this is to figure out how to use STI, ez_where, and
pagination.

Before STI and ez_where, I was building the conditions and setting up
pagination (ignore the fact that it was a session variable–that’s
gone now):

@person_pages, @people = paginate :person, :order => ‘last_name ASC,
first_name’,
:per_page => 20, :conditions
=> session[:conditions]

So, now, I’m building my conditions (one example):

  cond = Caboose::EZ::Condition.new :people do
    any :people do
      first_name =~ query
      last_name =~ query
      username =~ query
      preferred_name =~ query
    end
  end

And I could do the find like to:

@people = person_type.constantize.find :all, :order => ‘last_name ASC,
first_name’, :conditions => cond.to_sql

How does this fit into pagination? Yes, I can just put cond.to_sql in
for the condition, but I want to make sure I’m searching on the right
model. This doesn’t work:

@person_pages, @people = paginate person_type, :order => ‘last_name
ASC, first_name’,
:per_page => 20, :conditions =>
cond.to_sql

Nor does person_type.constantize. I think I tried adding the type to
the condition, but when searching for Employees, it didn’t translate
to Staff and Faculty. Should I have some sort of translation like
Rick suggested and add it to the ez_where conditions?

I’m just trying to figure out if I can do the equivalent of
Employee.find without resorting to that. Not that it’s so bad, but
the Employee.find searches seem more elegant.

Thanks!

Sean


#9

Sean-

I dont think it will work with the default paginator helper. You

need to build a custom paginator. Here is a good example:

http://rails.techno-weenie.net/question/2006/1/10/
passing_specific_records_to_the_paginator

Cheers-
-Ezra

On Feb 16, 2006, at 10:46 AM, Sean H. wrote:

@person_pages, @people = paginate :person, :order => 'last_name ASC,
username =~ query
for the condition, but I want to make sure I’m searching on the right
Rick suggested and add it to the ez_where conditions?

Constantize? Constantize!

person_type = “Employee”

@people = eval(person_type + ‘.find’ + ‘:all, :conditions => cond’)

someone was an employee and not either Faculty or Staff without
‘Faculty’]]

http://lists.rubyonrails.org/mailman/listinfo/rails

-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
removed_email_address@domain.invalid


#10

Sean-

Do an svn up on the ez_where plugin. I added an undef :type so that

the type column won’t interfere with the built in method anymore.
Hopefully it fixes things for you. Not sure about whether thers an
easier way to do what you want. I tend to stay away from STI myself.

-Ezra

On Feb 16, 2006, at 2:59 PM, Sean H. wrote:

to work off of finding (in the example) a category for blogs, and then
Faculty.find ok. I think I’m barking up the wrong tree. :confused: Maybe I

helper. You

      first_name =~ query

first_name’, :conditions => cond.to_sql
:per_page => 20, :conditions
the Employee.find searches seem more elegant.

On 2/15/06, Ezra Z. removed_email_address@domain.invalid wrote:

@people = Object.const_get(person_type).find :all, :conditions =>

know
This seems to work, except the conditions don’t come in
So, maybe the issue is with how I’m using the plugin and not the

that
Employee.find :all, :conditions => [“type IN (?)”, [‘Staff’,

removed_email_address@domain.invalid

http://lists.rubyonrails.org/mailman/listinfo/rails


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
removed_email_address@domain.invalid


#11

Oh, wow, nightmare:

cond_b = Caboose::EZ::Condition.new :people do
  type === ['Faculty', 'Staff']
end

cond_b is then nothing because type is a built-in method.
person[:type] in there is no good, either.

I can see where those particular paginators are going, but they seem
to work off of finding (in the example) a category for blogs, and then
working the pagination restricting to those blogs with that category.
Makes sense.

But as soon as I try to work in the Employee class, I end up with SQL
like “and type = ‘Employee’” which is not true anywhere. The parent
class is Employee, but as a type and main class, they’re Faculty or
Staff.

I somehow need to combine the way Rails finds subclasses with the
sql-ization of ez_where. I can do Employee.find, Staff.find, and
Faculty.find ok. I think I’m barking up the wrong tree. :confused: Maybe I
should do away with the STI altogether.

Back to the drawing board! :slight_smile: Thanks everyone!

Sean