Forum: Ruby on Rails STI Question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
2b2c2a705ed12f8fb327c7b4c56456c6?d=identicon&s=25 Sean Hussey (seanhussey)
on 2006-02-15 21:01
(Received via mailing list)
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
55428cbf149e35dd4b65f1d019d04139?d=identicon&s=25 Matthew Palmer (Guest)
on 2006-02-15 23:11
(Received via mailing list)
On Wed, Feb 15, 2006 at 02:59:38PM -0500, Sean Hussey 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
821395fe70906c8290df7f18ac4ac6cf?d=identicon&s=25 Rick Olson (Guest)
on 2006-02-15 23:21
(Received via mailing list)
> 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 Olson
http://techno-weenie.net
2b2c2a705ed12f8fb327c7b4c56456c6?d=identicon&s=25 Sean Hussey (seanhussey)
on 2006-02-15 23:39
(Received via mailing list)
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
132a94ca65959bda6c74fae54bff2425?d=identicon&s=25 Ezra Zygmuntowicz (Guest)
on 2006-02-16 01:06
(Received via mailing list)
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 Hussey 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
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>

-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
ezra@yakima-herald.com
132a94ca65959bda6c74fae54bff2425?d=identicon&s=25 Ezra Zygmuntowicz (Guest)
on 2006-02-16 01:06
(Received via mailing list)
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 Hussey 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
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>

-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
ezra@yakima-herald.com
2b2c2a705ed12f8fb327c7b4c56456c6?d=identicon&s=25 Sean Hussey (seanhussey)
on 2006-02-16 01:28
(Received via mailing list)
Constantize?  Constantize!

Ezra!  I kiss you!
2b2c2a705ed12f8fb327c7b4c56456c6?d=identicon&s=25 Sean Hussey (seanhussey)
on 2006-02-16 19:48
(Received via mailing list)
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
132a94ca65959bda6c74fae54bff2425?d=identicon&s=25 Ezra Zygmuntowicz (Guest)
on 2006-02-16 20:15
(Received via mailing list)
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 Hussey 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 Zygmuntowicz
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
ezra@yakima-herald.com
2b2c2a705ed12f8fb327c7b4c56456c6?d=identicon&s=25 Sean Hussey (seanhussey)
on 2006-02-17 00:02
(Received via mailing list)
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.  :/  Maybe I
should do away with the STI altogether.

Back to the drawing board!  :)  Thanks everyone!

Sean
132a94ca65959bda6c74fae54bff2425?d=identicon&s=25 Ezra Zygmuntowicz (Guest)
on 2006-02-17 00:35
(Received via mailing list)
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 Hussey 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.  :/  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 Zygmuntowicz <ezra@yakima-herald.com> 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',
>>>>>>>
>>>>>> Rails@lists.rubyonrails.org
>>>>>
>>> http://lists.rubyonrails.org/mailman/listinfo/rails
>>
>> _______________________________________________
>> Rails mailing list
>> Rails@lists.rubyonrails.org
>> http://lists.rubyonrails.org/mailman/listinfo/rails
>>
> _______________________________________________
> Rails mailing list
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>

-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
ezra@yakima-herald.com
This topic is locked and can not be replied to.